Working on performance issues.
diff --git a/com.google.eclipse.protobuf.ui/META-INF/MANIFEST.MF b/com.google.eclipse.protobuf.ui/META-INF/MANIFEST.MF
index 3cea5df..851a715 100644
--- a/com.google.eclipse.protobuf.ui/META-INF/MANIFEST.MF
+++ b/com.google.eclipse.protobuf.ui/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2

 Bundle-Name: %Bundle-Name

 Bundle-Vendor: %Bundle-Vendor

-Bundle-Version: 1.2.2.qualifier

+Bundle-Version: 1.2.3.qualifier

 Bundle-SymbolicName: com.google.eclipse.protobuf.ui; singleton:=true

 Bundle-ActivationPolicy: lazy

 Require-Bundle: com.google.eclipse.protobuf;visibility:=reexport,

diff --git a/com.google.eclipse.protobuf.ui/plugin.xml b/com.google.eclipse.protobuf.ui/plugin.xml
index 54a8999..f2fcf19 100644
--- a/com.google.eclipse.protobuf.ui/plugin.xml
+++ b/com.google.eclipse.protobuf.ui/plugin.xml
@@ -296,4 +296,10 @@
       </command>
     </menuContribution>
   </extension>
-</plugin>
\ No newline at end of file
+  <extension
+        point="org.eclipse.xtext.ui.shared.overridingGuiceModule">
+     <module
+           class="com.google.eclipse.protobuf.ui.ProtobufSharedModule">
+     </module>
+  </extension>
+</plugin>
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufSharedModule.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufSharedModule.java
new file mode 100644
index 0000000..9b58bd0
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufSharedModule.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2012 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.ui;
+
+import com.google.eclipse.protobuf.ui.builder.ProtobufBuilderState;
+import com.google.inject.*;
+import com.google.inject.name.Names;
+
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+import org.eclipse.ui.*;
+import org.eclipse.xtext.builder.builderState.IBuilderState;
+import org.eclipse.xtext.builder.clustering.ClusteringBuilderState;
+import org.eclipse.xtext.builder.impl.*;
+import org.eclipse.xtext.builder.resourceloader.*;
+import org.eclipse.xtext.resource.*;
+import org.eclipse.xtext.ui.editor.*;
+import org.eclipse.xtext.ui.notification.*;
+import org.eclipse.xtext.ui.resource.*;
+import org.eclipse.xtext.ui.shared.JdtHelper;
+import org.eclipse.xtext.ui.shared.internal.SharedModule;
+import org.eclipse.xtext.ui.util.IJdtHelper;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+@SuppressWarnings("restriction")
+public class ProtobufSharedModule extends SharedModule {
+
+  @Override protected void configure() {
+    bind(IBuilderState.class).to(ProtobufBuilderState.class).in(Scopes.SINGLETON);
+    bind(IResourceDescriptions.class).to(DirtyStateAwareResourceDescriptions.class).in(Scopes.SINGLETON);
+    bind(IResourceServiceProvider.Registry.class).toInstance(IResourceServiceProvider.Registry.INSTANCE);
+    bind(IResourceSetProvider.class).to(SimpleResourceSetProvider.class);
+    bind(IExtensionRegistry.class).toInstance(Platform.getExtensionRegistry());
+    bind(IResourceChangeListener.class).annotatedWith(Names.named(ProjectOpenedOrClosedListener.class.getName()))
+        .to(ProjectOpenedOrClosedListener.class);
+
+    bind(IExternalContentSupport.IExternalContentProvider.class).to(IDirtyStateManager.class).in(Scopes.SINGLETON);
+    bind(IDirtyStateManager.class).to(DirtyStateManager.class).in(Scopes.SINGLETON);
+    bind(IStateChangeEventBroker.class).to(StateChangeEventBroker.class).in(Scopes.SINGLETON);
+
+    bind(IncrementalProjectBuilder.class).to(XtextBuilder.class);
+    bind(IStorage2UriMapper.class).to(Storage2UriMapperImpl.class).in(Scopes.SINGLETON);
+
+    bind(IWorkbench.class).toProvider(new Provider<IWorkbench>() {
+      @Override public IWorkbench get() {
+        if (PlatformUI.isWorkbenchRunning()) {
+          return PlatformUI.getWorkbench();
+        }
+        return null;
+      }
+    });
+
+    bind(IWorkspace.class).toProvider(new Provider<IWorkspace>() {
+      @Override public IWorkspace get() {
+        return ResourcesPlugin.getWorkspace();
+      }
+    });
+
+    bind(IJdtHelper.class).to(JdtHelper.class).asEagerSingleton();
+
+    boolean parallel = false;
+    if (parallel) {
+      bind(IResourceLoader.class).toProvider(ResourceLoaderProviders.getParallelLoader());
+
+      bind(IResourceLoader.class).annotatedWith(Names.named(ClusteringBuilderState.RESOURCELOADER_GLOBAL_INDEX))
+          .toProvider(ResourceLoaderProviders.getParallelLoader());
+
+      bind(IResourceLoader.class).annotatedWith(Names.named(ClusteringBuilderState.RESOURCELOADER_CROSS_LINKING))
+          .toProvider(ResourceLoaderProviders.getParallelLoader());
+    } else {
+      bind(IResourceLoader.class).toProvider(ResourceLoaderProviders.getSerialLoader());
+
+      bind(IResourceLoader.class).annotatedWith(Names.named(ClusteringBuilderState.RESOURCELOADER_GLOBAL_INDEX))
+          .toProvider(ResourceLoaderProviders.getSerialLoader());
+
+      bind(IResourceLoader.class).annotatedWith(Names.named(ClusteringBuilderState.RESOURCELOADER_CROSS_LINKING))
+          .toProvider(ResourceLoaderProviders.getSerialLoader());
+    }
+
+  }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java
index c69af20..0edc76c 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/ProtobufUiModule.java
@@ -12,37 +12,16 @@
 import static com.google.inject.name.Names.named;
 import static org.eclipse.ui.PlatformUI.isWorkbenchRunning;
 
-import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
-import org.eclipse.jface.text.reconciler.IReconciler;
-import org.eclipse.ui.IWorkbenchWindow;
-import org.eclipse.ui.plugin.AbstractUIPlugin;
-import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
-import org.eclipse.xtext.documentation.IEObjectDocumentationProvider;
-import org.eclipse.xtext.parser.IParser;
-import org.eclipse.xtext.ui.LanguageSpecific;
-import org.eclipse.xtext.ui.editor.IURIEditorOpener;
-import org.eclipse.xtext.ui.editor.IXtextEditorCallback;
-import org.eclipse.xtext.ui.editor.model.XtextDocumentProvider;
-import org.eclipse.xtext.ui.editor.outline.actions.IOutlineContribution;
-import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreInitializer;
-import org.eclipse.xtext.ui.editor.quickfix.XtextQuickAssistProcessor;
-import org.eclipse.xtext.ui.editor.syntaxcoloring.IHighlightingConfiguration;
-import org.eclipse.xtext.ui.editor.syntaxcoloring.ISemanticHighlightingCalculator;
-import org.eclipse.xtext.ui.validation.IResourceUIValidatorExtension;
-
 import com.google.eclipse.protobuf.scoping.IFileUriResolver;
 import com.google.eclipse.protobuf.ui.builder.nature.AutoAddNatureEditorCallback;
 import com.google.eclipse.protobuf.ui.documentation.ProtobufDocumentationProvider;
-import com.google.eclipse.protobuf.ui.editor.FileOutsideWorkspaceIconUpdater;
-import com.google.eclipse.protobuf.ui.editor.ProtobufUriEditorOpener;
+import com.google.eclipse.protobuf.ui.editor.*;
 import com.google.eclipse.protobuf.ui.editor.hyperlinking.ProtobufHyperlinkDetector;
 import com.google.eclipse.protobuf.ui.editor.model.ProtobufDocumentProvider;
 import com.google.eclipse.protobuf.ui.editor.spelling.ProtobufReconciler;
-import com.google.eclipse.protobuf.ui.editor.syntaxcoloring.HighlightingConfiguration;
-import com.google.eclipse.protobuf.ui.editor.syntaxcoloring.ProtobufSemanticHighlightingCalculator;
+import com.google.eclipse.protobuf.ui.editor.syntaxcoloring.*;
 import com.google.eclipse.protobuf.ui.internal.ProtobufActivator;
-import com.google.eclipse.protobuf.ui.outline.LinkWithEditor;
-import com.google.eclipse.protobuf.ui.outline.ProtobufOutlinePage;
+import com.google.eclipse.protobuf.ui.outline.*;
 import com.google.eclipse.protobuf.ui.parser.PreferenceDrivenProtobufParser;
 import com.google.eclipse.protobuf.ui.preferences.compiler.core.CompilerPreferenceStoreInitializer;
 import com.google.eclipse.protobuf.ui.preferences.editor.numerictag.core.NumericTagPreferenceStoreInitializer;
@@ -52,10 +31,25 @@
 import com.google.eclipse.protobuf.ui.preferences.paths.core.PathsPreferenceStoreInitializer;
 import com.google.eclipse.protobuf.ui.quickfix.ProtobufQuickAssistProcessor;
 import com.google.eclipse.protobuf.ui.scoping.FileUriResolver;
-import com.google.eclipse.protobuf.ui.validation.ProtobufResourceUIValidatorExtension;
-import com.google.eclipse.protobuf.ui.validation.ValidateFileOnActivation;
+import com.google.eclipse.protobuf.ui.validation.*;
 import com.google.inject.Binder;
 
+import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
+import org.eclipse.jface.text.reconciler.IReconciler;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
+import org.eclipse.xtext.documentation.IEObjectDocumentationProvider;
+import org.eclipse.xtext.parser.IParser;
+import org.eclipse.xtext.ui.LanguageSpecific;
+import org.eclipse.xtext.ui.editor.*;
+import org.eclipse.xtext.ui.editor.model.XtextDocumentProvider;
+import org.eclipse.xtext.ui.editor.outline.actions.IOutlineContribution;
+import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreInitializer;
+import org.eclipse.xtext.ui.editor.quickfix.XtextQuickAssistProcessor;
+import org.eclipse.xtext.ui.editor.syntaxcoloring.*;
+import org.eclipse.xtext.ui.validation.IResourceUIValidatorExtension;
+
 /**
  * Use this class to register components to be used within the IDE.
  *
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/nature/resourceloader/ProtobufResourceLoaderProvider.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/nature/resourceloader/ProtobufResourceLoaderProvider.java
new file mode 100644
index 0000000..abb82e9
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/nature/resourceloader/ProtobufResourceLoaderProvider.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.ui.builder.nature.resourceloader;
+
+import org.eclipse.xtext.builder.resourceloader.*;
+import org.eclipse.xtext.builder.resourceloader.ResourceLoaderProviders.AbstractResourceLoaderProvider;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+@SuppressWarnings("restriction")
+public class ProtobufResourceLoaderProvider extends AbstractResourceLoaderProvider {
+  @Override public IResourceLoader get() {
+    return new ProtobufSerialResourceLoader(getResourceSetProvider(), getResourceSorter());
+  }
+}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/nature/resourceloader/ProtobufSerialResourceLoader.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/nature/resourceloader/ProtobufSerialResourceLoader.java
new file mode 100644
index 0000000..d7921cf
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/nature/resourceloader/ProtobufSerialResourceLoader.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.ui.builder.nature.resourceloader;
+
+import static com.google.common.collect.Collections2.filter;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Lists;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.emf.common.util.*;
+import org.eclipse.emf.ecore.resource.*;
+import org.eclipse.xtext.builder.resourceloader.SerialResourceLoader;
+import org.eclipse.xtext.ui.resource.IResourceSetProvider;
+
+import java.util.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+@SuppressWarnings("restriction")
+public class ProtobufSerialResourceLoader extends SerialResourceLoader {
+  public ProtobufSerialResourceLoader(IResourceSetProvider resourceSetProvider, Sorter sorter) {
+    super(resourceSetProvider, sorter);
+  }
+
+  @Override public LoadOperation create(final ResourceSet parent, IProject project) {
+    final Queue<URI> queue = Lists.newLinkedList();
+    return new CheckedLoadOperation(new LoadOperation() {
+      @Override public LoadResult next() {
+        URI uri = queue.poll();
+        try {
+          Resource resource = parent.getResource(uri, true);
+          return new LoadResult(resource, uri);
+        } catch (WrappedException e) {
+          throw new LoadOperationException(uri, e.getCause());
+        }
+      }
+
+      @Override public boolean hasNext() {
+        return !queue.isEmpty();
+      }
+
+      @Override public Collection<URI> cancel() {
+        return queue;
+      }
+
+      @Override public void load(Collection<URI> uris) {
+        Collection<URI> filtered = filter(uris, new Predicate<URI>() {
+          @Override public boolean apply(URI input) {
+            return !input.toString().endsWith("BulkMutatePayloadPseudoService.proto");
+          }
+        });
+        queue.addAll(getSorter().sort(filtered));
+      }
+    });
+  }
+
+}
diff --git a/com.google.eclipse.protobuf/META-INF/MANIFEST.MF b/com.google.eclipse.protobuf/META-INF/MANIFEST.MF
index 1bb9665..caafc24 100644
--- a/com.google.eclipse.protobuf/META-INF/MANIFEST.MF
+++ b/com.google.eclipse.protobuf/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Eclipse-ExtensibleAPI: true

 Bundle-Name: %Bundle-Name

 Bundle-Vendor: %Bundle-Vendor

-Bundle-Version: 1.2.2.qualifier

+Bundle-Version: 1.2.3.qualifier

 Bundle-SymbolicName: com.google.eclipse.protobuf; singleton:=true

 Bundle-ActivationPolicy: lazy

 Require-Bundle: org.eclipse.xtext;bundle-version="2.2.1",

diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/ProtobufQualifiedNameProvider.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/ProtobufQualifiedNameProvider.java
index fa070a7..8af9ccf 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/ProtobufQualifiedNameProvider.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/ProtobufQualifiedNameProvider.java
@@ -12,10 +12,13 @@
 import static org.eclipse.xtext.util.Tuples.pair;
 
 import com.google.eclipse.protobuf.model.util.*;
+import com.google.eclipse.protobuf.protobuf.*;
 import com.google.eclipse.protobuf.protobuf.Package;
 import com.google.inject.*;
 
+import org.eclipse.emf.common.util.URI;
 import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
 import org.eclipse.xtext.naming.*;
 import org.eclipse.xtext.util.*;
 
@@ -28,6 +31,8 @@
  */
 public class ProtobufQualifiedNameProvider extends IQualifiedNameProvider.AbstractImpl implements
     IProtobufQualifiedNameProvider {
+  private static final Class<?>[] IGNORED_TYPES = { Protobuf.class, Package.class, Import.class, Option.class, SimpleValueLink.class};
+
   private static final Pair<NameType, QualifiedName> EMPTY_NAME = pair(NORMAL, null);
 
   @Inject private final IQualifiedNameConverter converter = new IQualifiedNameConverter.DefaultImpl();
@@ -43,12 +48,25 @@
   }
 
   @Override public QualifiedName getFullyQualifiedName(final EObject e, final NamingStrategy namingStrategy) {
+//    final long start = System.currentTimeMillis();
+//    final AtomicLong end = new AtomicLong();
+//    final AtomicBoolean isCached = new AtomicBoolean(true);
+    for (Class<?> ignored : IGNORED_TYPES) {
+      if (ignored.isInstance(e)) {
+        return null;
+      }
+    }
     Pair<EObject, String> key = pair(e, "fqn");
-    Pair<NameType, QualifiedName> cached = cache.get(key, e.eResource(), new Provider<Pair<NameType, QualifiedName>>() {
+    Resource resource = e.eResource();
+    URI uri = resource.getURI();
+//    System.out.println(uri);
+    Pair<NameType, QualifiedName> cached = cache.get(key, resource, new Provider<Pair<NameType, QualifiedName>>() {
       @Override public Pair<NameType, QualifiedName> get() {
+//        isCached.set(false);
         EObject current = e;
         Pair<NameType, String> name = namingStrategy.nameOf(e);
         if (name == null) {
+//          end.set(System.currentTimeMillis());
           return EMPTY_NAME;
         }
         QualifiedName qualifiedName = converter.toQualifiedName(name.getSecond());
@@ -56,13 +74,21 @@
           current = current.eContainer();
           QualifiedName parentsQualifiedName = getFullyQualifiedName(current, namingStrategy);
           if (parentsQualifiedName != null) {
+//            end.set(System.currentTimeMillis());
             return pair(name.getFirst(), parentsQualifiedName.append(qualifiedName));
           }
         }
+//        end.set(System.currentTimeMillis());
         return pair(name.getFirst(), addPackage(e, qualifiedName));
       }
     });
-    return cached.getSecond();
+    QualifiedName qualifiedName = cached.getSecond();
+//    if (isCached.get()) {
+//      end.set(System.currentTimeMillis());
+//    }
+//    double seconds = (end.get() - start) / 1000;
+//    System.out.println("URI: " + uri.toString() + ", type: " + e.getClass().getSimpleName() + ", qualified name: " + qualifiedName + ", cached? " + isCached.get() + ", time: " + seconds);
+    return qualifiedName;
   }
 
   private QualifiedName addPackage(EObject obj, QualifiedName qualifiedName) {
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufResourceValidator.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufResourceValidator.java
index f161e5a..f8d2d33 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufResourceValidator.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufResourceValidator.java
@@ -18,10 +18,10 @@
 import static org.eclipse.xtext.validation.CheckType.FAST;
 import static org.eclipse.xtext.validation.impl.ConcreteSyntaxEValidator.DISABLE_CONCRETE_SYNTAX_EVALIDATOR;
 
-import java.util.*;
+import com.google.eclipse.protobuf.linking.ProtobufDiagnostic;
 
 import org.apache.log4j.Logger;
-import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.common.util.*;
 import org.eclipse.emf.ecore.*;
 import org.eclipse.emf.ecore.resource.Resource;
 import org.eclipse.xtext.diagnostics.Severity;
@@ -29,7 +29,7 @@
 import org.eclipse.xtext.util.*;
 import org.eclipse.xtext.validation.*;
 
-import com.google.eclipse.protobuf.linking.ProtobufDiagnostic;
+import java.util.*;
 
 /**
  * Adds support for converting scoping errors into warnings if non-proto2 files are imported.
@@ -41,7 +41,17 @@
 
   @Override public List<Issue> validate(Resource resource, CheckMode mode, CancelIndicator indicator) {
     CancelIndicator monitor = indicator == null ? CancelIndicator.NullImpl : indicator;
-    resolveProxies(resource, monitor);
+//    long start = System.currentTimeMillis();
+    URI uri = resource.getURI();
+    if (uri.toString().endsWith("BulkMutatePayloadPseudoService.proto")) {
+      System.out.println("Ignoring validation BulkMutatePayloadPseudoService.proto");
+    } else {
+      resolveProxies(resource, monitor);
+    }
+//    long end = System.currentTimeMillis();
+//    long total = end - start;
+//
+//    System.out.println("Validated: " + resource.getURI() + " in " + total);
     if (monitor.isCanceled()) {
       return null;
     }