diff --git a/src/lint/engine/ArcanistLintEngine.php b/src/lint/engine/ArcanistLintEngine.php
--- a/src/lint/engine/ArcanistLintEngine.php
+++ b/src/lint/engine/ArcanistLintEngine.php
@@ -65,6 +65,8 @@
   private $postponedLinters = array();
   private $configurationManager;
 
+  private $linterResources = array();
+
   public function __construct() {
 
   }
@@ -548,4 +550,38 @@
   }
 
 
+  /**
+   * Get a named linter resource shared by another linter.
+   *
+   * This mechanism allows linters to share arbitrary resources, like the
+   * results of computation. If several linters need to perform the same
+   * expensive computation step, they can use a named resource to synchronize
+   * construction of the result so it doesn't need to be built multiple
+   * times.
+   *
+   * @param string  Resource identifier.
+   * @param wild    Optionally, default value to return if resource does not
+   *                exist.
+   * @return wild   Resource, or default value if not present.
+   */
+  public function getLinterResource($key, $default = null) {
+    return idx($this->linterResources, $key, $default);
+  }
+
+
+  /**
+   * Set a linter resource that other linters can accesss.
+   *
+   * See @{method:getLinterResource} for a description of this mechanism.
+   *
+   * @param string Resource identifier.
+   * @param wild   Resource.
+   * @return this
+   */
+  public function setLinterResource($key, $value) {
+    $this->linterResources[$key] = $value;
+    return $this;
+  }
+
+
 }
diff --git a/src/lint/engine/PhutilLintEngine.php b/src/lint/engine/PhutilLintEngine.php
--- a/src/lint/engine/PhutilLintEngine.php
+++ b/src/lint/engine/PhutilLintEngine.php
@@ -58,7 +58,6 @@
     $linters[] = $xhpast_linter;
 
     $linters[] = id(new ArcanistPhutilXHPASTLinter())
-      ->setXHPASTLinter($xhpast_linter)
       ->setPaths($php_paths);
 
     $merge_conflict_linter = id(new ArcanistMergeConflictLinter());
diff --git a/src/lint/linter/ArcanistBaseXHPASTLinter.php b/src/lint/linter/ArcanistBaseXHPASTLinter.php
--- a/src/lint/linter/ArcanistBaseXHPASTLinter.php
+++ b/src/lint/linter/ArcanistBaseXHPASTLinter.php
@@ -1,8 +1,5 @@
 <?php
 
-/**
- * @group linter
- */
 abstract class ArcanistBaseXHPASTLinter extends ArcanistFutureLinter {
 
   protected final function raiseLintAtToken(
diff --git a/src/lint/linter/ArcanistPhutilXHPASTLinter.php b/src/lint/linter/ArcanistPhutilXHPASTLinter.php
--- a/src/lint/linter/ArcanistPhutilXHPASTLinter.php
+++ b/src/lint/linter/ArcanistPhutilXHPASTLinter.php
@@ -1,22 +1,19 @@
 <?php
 
-/**
- * @group linter
- */
 final class ArcanistPhutilXHPASTLinter extends ArcanistBaseXHPASTLinter {
 
   const LINT_ARRAY_COMBINE           = 2;
   const LINT_DEPRECATED_FUNCTION     = 3;
   const LINT_UNSAFE_DYNAMIC_STRING   = 4;
 
-  private $xhpastLinter;
   private $deprecatedFunctions = array();
   private $dynamicStringFunctions = array();
   private $dynamicStringClasses = array();
 
-  public function setXHPASTLinter(ArcanistXHPASTLinter $linter) {
-    $this->xhpastLinter = $linter;
-    return $this;
+  public function getLinterPriority() {
+    // Make sure this runs after XHPASTLinter so we can reuse the parse tree
+    // if it's available.
+    return 2.0;
   }
 
   public function setDeprecatedFunctions($map) {
@@ -34,15 +31,6 @@
     return $this;
   }
 
-  public function setEngine(ArcanistLintEngine $engine) {
-    if (!$this->xhpastLinter) {
-      throw new Exception(
-        'Call setXHPASTLinter() before using ArcanistPhutilXHPASTLinter.');
-    }
-    $this->xhpastLinter->setEngine($engine);
-    return parent::setEngine($engine);
-  }
-
   public function getLintNameMap() {
     return array(
       self::LINT_ARRAY_COMBINE           => 'array_combine() Unreliable',
@@ -73,17 +61,30 @@
     return $version;
   }
 
+  private function getXHPASTLinter() {
+    // If possible, reuse the parse tree generated by an existing vanilla
+    // XHPASTLinter. Otherwise, provide one as a shared resource.
+    $engine = $this->getEngine();
+    $linter = $engine->getLinterResource('xhpast.linter');
+    if (!$linter) {
+      $linter = new ArcanistXHPASTLinter();
+      $linter->setEngine($engine);
+      $engine->setLinterResource('xhpast.linter', $linter);
+    }
+    return $linter;
+  }
+
   protected function buildFutures(array $paths) {
-    return $this->xhpastLinter->buildFutures($paths);
+    return $this->getXHPASTLinter()->buildFutures($paths);
   }
 
   public function willLintPath($path) {
-    $this->xhpastLinter->willLintPath($path);
+    $this->getXHPASTLinter()->willLintPath($path);
     return parent::willLintPath($path);
   }
 
   protected function resolveFuture($path, Future $future) {
-    $tree = $this->xhpastLinter->getXHPASTTreeForPath($path);
+    $tree = $this->getXHPASTLinter()->getXHPASTTreeForPath($path);
     if (!$tree) {
       return;
     }
diff --git a/src/lint/linter/ArcanistXHPASTLinter.php b/src/lint/linter/ArcanistXHPASTLinter.php
--- a/src/lint/linter/ArcanistXHPASTLinter.php
+++ b/src/lint/linter/ArcanistXHPASTLinter.php
@@ -92,6 +92,18 @@
     );
   }
 
+  public function willLintPaths(array $paths) {
+    // If nothing has shared an XHPASTLinter yet, provide this linter as a
+    // shared resource. Other linters which rely on the parse tree will be
+    // able to reuse the one this linter generates.
+    $engine = $this->getEngine();
+    if (!$engine->getLinterResource('xhpast.linter')) {
+      $engine->setLinterResource('xhpast.linter', $this);
+    }
+
+    return parent::willLintPaths($paths);
+  }
+
   public function getLinterName() {
     return 'XHP';
   }
diff --git a/src/lint/linter/__tests__/ArcanistPhutilXHPASTLinterTestCase.php b/src/lint/linter/__tests__/ArcanistPhutilXHPASTLinterTestCase.php
--- a/src/lint/linter/__tests__/ArcanistPhutilXHPASTLinterTestCase.php
+++ b/src/lint/linter/__tests__/ArcanistPhutilXHPASTLinterTestCase.php
@@ -8,7 +8,6 @@
 
   public function testPhutilXHPASTLint() {
     $linter = new ArcanistPhutilXHPASTLinter();
-    $linter->setXHPASTLinter(new ArcanistXHPASTLinter());
     $linter->setDeprecatedFunctions(array(
       'deprecated_function' => 'This function is most likely deprecated.',
     ));