Refactor the GN threading model to reduce locking and simplify execution.

Old design: item_tree manages dependency resolution, target_manager creates and hooks up the target dependencies, and the toolchain manager does all kinds of crazy ordering and loading stuff on every thread. There is lots of locking every time the dependency tree is modified.

This patch completely deletes the toolchain manager, item tree, item node, and target manager.

The new design is that the build files are executed on background threads, but then they come back to the main thread which assembles the dependency tree and schedules other file loads. This eliminates almost all locking and a lot of complexity.

The Loader now manages loading the different build files in the correct context, and managing dependencies (loading the build config first, for example). The Builder manages the dependency tree and requests that the Loader load files that it encounters references to.

This simpler design reduces non-test code by ~350 lines. In the current gn build, lock acquisitions go down from 1808 to 116 and it saves about 20ms wall clock time (8% faster). This is a bit deceiving, though, because most of the time is spent on pkg-config which is constant. It speeds up running individual build files by 1000-1500%.

The work of putting the tree together that used to take up this time inside locks is now transferred to the main thread, which looks like it is *sometimes* a bottleneck. This should be easier to optimize in the future, though.

Other tweaks:
 - I fixed cycle finding
 - Directories look prettier on Windows using the "desc" command
 - Tracing output now includes the main thread and marks it as such
 - I updated the base BUILD.gn file for the more recent tree.

R=scottmg@chromium.org

Review URL: https://codereview.chromium.org/56433003

Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 26542b05b057b860dda4fe73a8ab179b86bccadd
diff --git a/tools/gn/BUILD.gn b/tools/gn/BUILD.gn
index c5cc1cb..43ca2d1 100644
--- a/tools/gn/BUILD.gn
+++ b/tools/gn/BUILD.gn
@@ -16,6 +16,10 @@
     "binary_target_generator.h",
     "build_settings.cc",
     "build_settings.h",
+    "builder.cc",
+    "builder.h",
+    "builder_record.cc",
+    "builder_record.h",
     "command_args.cc",
     "command_desc.cc",
     "command_gen.cc",
@@ -72,13 +76,11 @@
     "input_file_manager.h",
     "item.cc",
     "item.h",
-    "item_node.cc",
-    "item_node.h",
-    "item_tree.cc",
-    "item_tree.h",
     "label.cc",
     "label.h",
     "label_ptr.h",
+    "loader.cc",
+    "loader.h",
     "location.cc",
     "location.h",
     "ninja_binary_target_writer.cc",
@@ -136,16 +138,12 @@
     "target.h",
     "target_generator.cc",
     "target_generator.h",
-    "target_manager.cc",
-    "target_manager.h",
     "token.cc",
     "token.h",
     "tokenizer.cc",
     "tokenizer.h",
     "toolchain.cc",
     "toolchain.h",
-    "toolchain_manager.cc",
-    "toolchain_manager.h",
     "trace.cc",
     "trace.h",
     "value.cc",
@@ -159,7 +157,6 @@
   deps = [
     "//base",
     "//base/third_party/dynamic_annotations",
-    "//build/util:last_change",
   ]
 }
 
@@ -170,17 +167,20 @@
 
   deps = [
     ":gn_lib",
+    "//build/util:last_change",
   ]
 }
 
 test("gn_unittests") {
   sources = [
+    "builder_unittest.cc",
     "escape_unittest.cc",
     "file_template_unittest.cc",
     "filesystem_utils_unittest.cc",
     "function_rebase_path_unittest.cc",
     "input_conversion_unittest.cc",
     "label_unittest.cc",
+    "loader_unittest.cc",
     "ninja_binary_target_writer_unittest.cc",
     "ninja_copy_target_writer_unittest.cc",
     "ninja_helper_unittest.cc",
@@ -192,7 +192,6 @@
     "source_dir_unittest.cc",
     "string_utils_unittest.cc",
     "target_generator_unittest.cc",
-    "target_manager_unittest.cc",
     "target_unittest.cc",
     "test_with_scope.cc",
     "test_with_scope.h",
diff --git a/tools/gn/bin/linux/gn.sha1 b/tools/gn/bin/linux/gn.sha1
index af60316..92e7e20 100644
--- a/tools/gn/bin/linux/gn.sha1
+++ b/tools/gn/bin/linux/gn.sha1
@@ -1 +1 @@
-9c71ff30a0781745029d018313783cc814a8c305
\ No newline at end of file
+bca8a009781cf114d357cd73323bddeca8ac33e3

diff --git a/tools/gn/bin/win/gn.exe.sha1 b/tools/gn/bin/win/gn.exe.sha1
index 492ffbc..19440ce 100644
--- a/tools/gn/bin/win/gn.exe.sha1
+++ b/tools/gn/bin/win/gn.exe.sha1
@@ -1 +1 @@
-afd819eef0c7a347b4021ac47b722e04e9ff3193
\ No newline at end of file
+d8b10289afc05f38d0e4581ed093069424d58634
\ No newline at end of file
diff --git a/tools/gn/binary_target_generator.cc b/tools/gn/binary_target_generator.cc
index b8d2d6e..3aec119 100644
--- a/tools/gn/binary_target_generator.cc
+++ b/tools/gn/binary_target_generator.cc
@@ -9,12 +9,13 @@
 #include "tools/gn/scope.h"
 #include "tools/gn/variables.h"
 
-BinaryTargetGenerator::BinaryTargetGenerator(Target* target,
-                                             Scope* scope,
-                                             const Token& function_token,
-                                             Target::OutputType type,
-                                             Err* err)
-    : TargetGenerator(target, scope, function_token, err),
+BinaryTargetGenerator::BinaryTargetGenerator(
+    Target* target,
+    Scope* scope,
+    const FunctionCallNode* function_call,
+    Target::OutputType type,
+    Err* err)
+    : TargetGenerator(target, scope, function_call, err),
       output_type_(type) {
 }
 
@@ -46,12 +47,10 @@
 
   // Config values (compiler flags, etc.) set directly on this target.
   ConfigValuesGenerator gen(&target_->config_values(), scope_,
-                            function_token_, scope_->GetSourceDir(), err_);
+                            scope_->GetSourceDir(), err_);
   gen.Run();
   if (err_->has_error())
     return;
-
-  SetToolchainDependency();
 }
 
 void BinaryTargetGenerator::FillOutputName() {
diff --git a/tools/gn/binary_target_generator.h b/tools/gn/binary_target_generator.h
index f0b42ea..d4db096 100644
--- a/tools/gn/binary_target_generator.h
+++ b/tools/gn/binary_target_generator.h
@@ -14,7 +14,7 @@
  public:
   BinaryTargetGenerator(Target* target,
                         Scope* scope,
-                        const Token& function_token,
+                        const FunctionCallNode* function_call,
                         Target::OutputType type,
                         Err* err);
   virtual ~BinaryTargetGenerator();
diff --git a/tools/gn/build_settings.cc b/tools/gn/build_settings.cc
index 0a75569..7d1bcf0 100644
--- a/tools/gn/build_settings.cc
+++ b/tools/gn/build_settings.cc
@@ -7,27 +7,18 @@
 #include "base/file_util.h"
 #include "tools/gn/filesystem_utils.h"
 
-BuildSettings::BuildSettings()
-    : using_external_generator_(false),
-      item_tree_(),
-      target_manager_(this),
-      toolchain_manager_(this) {
+BuildSettings::BuildSettings() {
 }
 
 BuildSettings::BuildSettings(const BuildSettings& other)
     : root_path_(other.root_path_),
       root_path_utf8_(other.root_path_utf8_),
       secondary_source_path_(other.secondary_source_path_),
-      using_external_generator_(other.using_external_generator_),
       python_path_(other.python_path_),
       build_config_file_(other.build_config_file_),
       build_dir_(other.build_dir_),
       build_to_source_dir_string_(other.build_to_source_dir_string_),
-      build_args_(other.build_args_),
-      target_resolved_callback_(),  // Don't copy.
-      item_tree_(),
-      target_manager_(this),
-      toolchain_manager_(this) {
+      build_args_(other.build_args_) {
 }
 
 BuildSettings::~BuildSettings() {
@@ -66,3 +57,8 @@
   return dir.Resolve(secondary_source_path_);
 }
 
+void BuildSettings::ItemDefined(scoped_ptr<Item> item) const {
+  DCHECK(item);
+  if (!item_defined_callback_.is_null())
+    item_defined_callback_.Run(item.Pass());
+}
diff --git a/tools/gn/build_settings.h b/tools/gn/build_settings.h
index fc175df..2e93296 100644
--- a/tools/gn/build_settings.h
+++ b/tools/gn/build_settings.h
@@ -10,21 +10,20 @@
 #include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
 #include "tools/gn/args.h"
-#include "tools/gn/item_tree.h"
 #include "tools/gn/scope.h"
 #include "tools/gn/source_dir.h"
 #include "tools/gn/source_file.h"
-#include "tools/gn/target_manager.h"
-#include "tools/gn/toolchain_manager.h"
 
+class Item;
 class OutputFile;
 
 // Settings for one build, which is one toplevel output directory. There
 // may be multiple Settings objects that refer to this, one for each toolchain.
 class BuildSettings {
  public:
-  typedef base::Callback<void(const Target*)> TargetResolvedCallback;
+  typedef base::Callback<void(scoped_ptr<Item>)> ItemDefinedCallback;
 
   BuildSettings();
   BuildSettings(const BuildSettings& other);
@@ -44,13 +43,6 @@
   }
   void SetSecondarySourcePath(const SourceDir& d);
 
-  // Set when we're running an external generator (e.g. GYP) and should
-  // enable "external" flags on targets.
-  bool using_external_generator() const { return using_external_generator_; }
-  void set_using_external_generator(bool ueg) {
-    using_external_generator_ = ueg;
-  }
-
   // Path of the python executable to run scripts with.
   base::FilePath python_path() const { return python_path_; }
   void set_python_path(const base::FilePath& p) { python_path_ = p; }
@@ -74,16 +66,6 @@
   Args& build_args() { return build_args_; }
   const Args& build_args() const { return build_args_; }
 
-  // These accessors do not return const objects since the resulting objects
-  // are threadsafe. In this setting, we use constness primarily to ensure
-  // that the Settings object is used in a threadsafe manner. Although this
-  // violates the concept of logical constness, that's less important in our
-  // application, and actually implementing this in a way that preserves
-  // logical constness is cumbersome.
-  ItemTree& item_tree() const { return item_tree_; }
-  TargetManager& target_manager() const { return target_manager_; }
-  ToolchainManager& toolchain_manager() const { return toolchain_manager_; }
-
   // Returns the full absolute OS path cooresponding to the given file in the
   // root source tree.
   base::FilePath GetFullPath(const SourceFile& file) const;
@@ -95,22 +77,16 @@
   base::FilePath GetFullPathSecondary(const SourceFile& file) const;
   base::FilePath GetFullPathSecondary(const SourceDir& dir) const;
 
-  // This is the callback to execute when a target is marked resolved. If we
-  // don't need to do anything, this will be null. When a target is resolved,
-  // this callback should be posted to the scheduler pool so the work is
-  // distributed properly.
-  const TargetResolvedCallback& target_resolved_callback() const {
-    return target_resolved_callback_;
-  }
-  void set_target_resolved_callback(const TargetResolvedCallback& cb) {
-    target_resolved_callback_ = cb;
+  // Called when an item is defined from a background thread.
+  void ItemDefined(scoped_ptr<Item> item) const;
+  void set_item_defined_callback(ItemDefinedCallback cb) {
+    item_defined_callback_ = cb;
   }
 
  private:
   base::FilePath root_path_;
   std::string root_path_utf8_;
   base::FilePath secondary_source_path_;
-  bool using_external_generator_;
   base::FilePath python_path_;
 
   SourceFile build_config_file_;
@@ -118,12 +94,7 @@
   std::string build_to_source_dir_string_;
   Args build_args_;
 
-  TargetResolvedCallback target_resolved_callback_;
-
-  // See getters above.
-  mutable ItemTree item_tree_;
-  mutable TargetManager target_manager_;
-  mutable ToolchainManager toolchain_manager_;
+  ItemDefinedCallback item_defined_callback_;
 
   BuildSettings& operator=(const BuildSettings& other);  // Disallow.
 };
diff --git a/tools/gn/builder.cc b/tools/gn/builder.cc
new file mode 100644
index 0000000..07a308b
--- /dev/null
+++ b/tools/gn/builder.cc
@@ -0,0 +1,471 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "tools/gn/builder.h"
+
+#include "tools/gn/config.h"
+#include "tools/gn/err.h"
+#include "tools/gn/loader.h"
+#include "tools/gn/scheduler.h"
+#include "tools/gn/settings.h"
+#include "tools/gn/target.h"
+#include "tools/gn/trace.h"
+
+namespace {
+
+typedef BuilderRecord::BuilderRecordSet BuilderRecordSet;
+
+// Recursively looks in the tree for a given node, returning true if it
+// was found in the dependecy graph. This is used to see if a given node
+// participates in a cycle.
+//
+// If this returns true, the cycle will be in *path. This should point to an
+// empty vector for the first call. During computation, the path will contain
+// the full dependency path to the current node.
+//
+// Return false means no cycle was found.
+bool RecursiveFindCycle(const BuilderRecord* search_in,
+                        std::vector<const BuilderRecord*>* path) {
+  path->push_back(search_in);
+
+  const BuilderRecord::BuilderRecordSet& unresolved =
+      search_in->unresolved_deps();
+  for (BuilderRecord::BuilderRecordSet::const_iterator i = unresolved.begin();
+       i != unresolved.end(); ++i) {
+    const BuilderRecord* cur = *i;
+
+    std::vector<const BuilderRecord*>::iterator found =
+        std::find(path->begin(), path->end(), cur);
+    if (found != path->end()) {
+      // This item is already in the set, we found the cycle. Everything before
+      // the first definition of cur is irrelevant to the cycle.
+      path->erase(path->begin(), found);
+      path->push_back(cur);
+      return true;
+    }
+
+    if (RecursiveFindCycle(cur, path))
+      return true;  // Found cycle.
+  }
+  path->pop_back();
+  return false;
+}
+
+}  // namespace
+
+Builder::Builder(Loader* loader) : loader_(loader) {
+}
+
+Builder::~Builder() {
+}
+
+void Builder::ItemDefined(scoped_ptr<Item> item) {
+  ScopedTrace trace(TraceItem::TRACE_DEFINE_TARGET, item->label());
+  trace.SetToolchain(item->settings()->toolchain_label());
+
+  BuilderRecord::ItemType type = BuilderRecord::TypeOfItem(item.get());
+
+  Err err;
+  BuilderRecord* record =
+      GetOrCreateRecordOfType(item->label(), item->defined_from(), type, &err);
+  if (!record) {
+    g_scheduler->FailWithError(err);
+    return;
+  }
+
+  // Check that it's not been already defined.
+  if (record->item()) {
+    err = Err(item->defined_from(), "Duplicate definition.",
+        "The item\n  " + item->label().GetUserVisibleName(false) +
+        "\nwas already defined.");
+    err.AppendSubErr(Err(record->item()->defined_from(),
+                         "Previous definition:"));
+    g_scheduler->FailWithError(err);
+    return;
+  }
+
+  record->set_item(item.Pass());
+
+  // Do target-specific dependency setup. This will also schedule dependency
+  // loads for targets that are required.
+  switch (type) {
+    case BuilderRecord::ITEM_TARGET:
+      if (!TargetDefined(record, &err)) {
+        g_scheduler->FailWithError(err);
+        return;
+      }
+      break;
+    case BuilderRecord::ITEM_TOOLCHAIN:
+      loader_->ToolchainLoaded(record->item()->AsToolchain());
+      break;
+    default:
+      break;
+  }
+
+  if (record->can_resolve()) {
+    if (!ResolveItem(record, &err)) {
+      g_scheduler->FailWithError(err);
+      return;
+    }
+  }
+}
+
+const Item* Builder::GetItem(const Label& label) const {
+  const BuilderRecord* record = GetRecord(label);
+  if (!record)
+    return NULL;
+  return record->item();
+}
+
+const Toolchain* Builder::GetToolchain(const Label& label) const {
+  const BuilderRecord* record = GetRecord(label);
+  if (!record)
+    return NULL;
+  if (!record->item())
+    return NULL;
+  return record->item()->AsToolchain();
+}
+
+std::vector<const BuilderRecord*> Builder::GetAllRecords() const {
+  std::vector<const BuilderRecord*> result;
+  result.reserve(records_.size());
+  for (RecordMap::const_iterator i = records_.begin();
+       i != records_.end(); ++i)
+    result.push_back(i->second);
+  return result;
+}
+
+std::vector<const Target*> Builder::GetAllResolvedTargets() const {
+  std::vector<const Target*> result;
+  result.reserve(records_.size());
+  for (RecordMap::const_iterator i = records_.begin();
+       i != records_.end(); ++i) {
+    if (i->second->type() == BuilderRecord::ITEM_TARGET &&
+        i->second->should_generate() && i->second->item())
+      result.push_back(i->second->item()->AsTarget());
+  }
+  return result;
+}
+
+const BuilderRecord* Builder::GetRecord(const Label& label) const {
+  // Forward to the non-const version.
+  return const_cast<Builder*>(this)->GetRecord(label);
+}
+
+BuilderRecord* Builder::GetRecord(const Label& label) {
+  RecordMap::iterator found = records_.find(label);
+  if (found == records_.end())
+    return NULL;
+  return found->second;
+}
+
+bool Builder::CheckForBadItems(Err* err) const {
+  // Look for errors where we find a defined node with an item that refers to
+  // an undefined one with no item. There may be other nodes in turn depending
+  // on our defined one, but listing those isn't helpful: we want to find the
+  // broken link.
+  //
+  // This finds normal "missing dependency" errors but does not find circular
+  // dependencies because in this case all items in the cycle will be GENERATED
+  // but none will be resolved. If this happens, we'll check explicitly for
+  // that below.
+  std::vector<const BuilderRecord*> bad_records;
+  std::string depstring;
+  for (RecordMap::const_iterator i = records_.begin();
+       i != records_.end(); ++i) {
+    const BuilderRecord* src = i->second;
+    if (!src->should_generate())
+      continue;  // Skip ungenerated nodes.
+
+    if (!src->resolved()) {
+      bad_records.push_back(src);
+
+      // Check dependencies.
+      for (BuilderRecord::BuilderRecordSet::const_iterator dest_iter =
+               src->unresolved_deps().begin();
+          dest_iter != src->unresolved_deps().end();
+          ++dest_iter) {
+        const BuilderRecord* dest = *dest_iter;
+        if (!dest->item()) {
+          depstring += src->label().GetUserVisibleName(true) +
+              "\n  needs " + dest->label().GetUserVisibleName(true) + "\n";
+        }
+      }
+    }
+  }
+
+  if (!depstring.empty()) {
+    *err = Err(Location(), "Unresolved dependencies.", depstring);
+    return false;
+  }
+
+  if (!bad_records.empty()) {
+    // Our logic above found a bad node but didn't identify the problem. This
+    // normally means a circular dependency.
+    depstring = CheckForCircularDependencies(bad_records);
+    if (depstring.empty()) {
+      // Something's very wrong, just dump out the bad nodes.
+      depstring = "I have no idea what went wrong, but these are unresolved, "
+          "possible due to an\ninternal error:";
+      for (size_t i = 0; i < bad_records.size(); i++) {
+        depstring += "\n\"" +
+            bad_records[i]->label().GetUserVisibleName(false) + "\"";
+      }
+      *err = Err(Location(), "", depstring);
+    } else {
+      *err = Err(Location(), "Dependency cycle:", depstring);
+    }
+    return false;
+  }
+
+  return true;
+}
+
+bool Builder::TargetDefined(BuilderRecord* record, Err* err) {
+  Target* target = record->item()->AsTarget();
+
+  if (!AddDeps(record, target->deps(), err) ||
+      !AddDeps(record, target->datadeps(), err) ||
+      !AddDeps(record, target->configs(), err) ||
+      !AddDeps(record, target->all_dependent_configs(), err) ||
+      !AddDeps(record, target->direct_dependent_configs(), err) ||
+      !AddToolchainDep(record, target, err))
+    return false;
+
+  // All targets in the default toolchain get generated by default. We also
+  // check if this target was previously marked as "required" and force setting
+  // the bit again so the target's dependencies (which we now know) get the
+  // required bit pushed to them.
+  if (record->should_generate() || target->settings()->is_default())
+    RecursiveSetShouldGenerate(record, true);
+
+  return true;
+}
+
+BuilderRecord* Builder::GetOrCreateRecordOfType(const Label& label,
+                                                const ParseNode* request_from,
+                                                BuilderRecord::ItemType type,
+                                                Err* err) {
+  BuilderRecord* record = GetRecord(label);
+  if (!record) {
+    // Not seen this record yet, create a new one.
+    record = new BuilderRecord(type, label);
+    records_[label] = record;
+    return record;
+  }
+
+  // Check types.
+  if (record->type() != type) {
+    *err = Err(request_from, "Item type does not match.",
+        "The item \"" + label.GetUserVisibleName(false) +
+        "\" was expected\nto be a " +
+        BuilderRecord::GetNameForType(type) +
+        " but was previously\n referenced as a " +
+        BuilderRecord::GetNameForType(record->type()));
+    err->AppendSubErr(Err(record->originally_referenced_from(),
+                          "The previous reference was here."));
+    return NULL;
+  }
+
+  return record;
+}
+
+BuilderRecord* Builder::GetResolvedRecordOfType(const Label& label,
+                                                const ParseNode* origin,
+                                                BuilderRecord::ItemType type,
+                                                Err* err) {
+  BuilderRecord* record = GetRecord(label);
+  if (!record) {
+    *err = Err(origin, "Item not found",
+        "\"" + label.GetUserVisibleName(false) + "\" doesn't\n"
+        "refer to an existant thing.");
+    return NULL;
+  }
+
+  const Item* item = record->item();
+  if (!item) {
+    *err = Err(origin, "Item not resolved.",
+        "\"" + label.GetUserVisibleName(false) + "\" hasn't been resolved.\n");
+    return NULL;
+  }
+
+  if (!BuilderRecord::IsItemOfType(item, type)) {
+    *err = Err(origin,
+        std::string("This is not a ") + BuilderRecord::GetNameForType(type),
+        "\"" + label.GetUserVisibleName(false) + "\" refers to a " +
+        item->GetItemTypeName() + " instead of a " +
+        BuilderRecord::GetNameForType(type) + ".");
+    return NULL;
+  }
+  return record;
+}
+
+bool Builder::AddDeps(BuilderRecord* record,
+                      const LabelConfigVector& configs,
+                      Err* err) {
+  for (size_t i = 0; i < configs.size(); i++) {
+    BuilderRecord* dep_record = GetOrCreateRecordOfType(
+        configs[i].label, configs[i].origin, BuilderRecord::ITEM_CONFIG, err);
+    if (!dep_record)
+      return false;
+    record->AddDep(dep_record);
+  }
+  return true;
+}
+
+bool Builder::AddDeps(BuilderRecord* record,
+                      const LabelTargetVector& targets,
+                      Err* err) {
+  for (size_t i = 0; i < targets.size(); i++) {
+    BuilderRecord* dep_record = GetOrCreateRecordOfType(
+        targets[i].label, targets[i].origin, BuilderRecord::ITEM_TARGET, err);
+    if (!dep_record)
+      return false;
+    record->AddDep(dep_record);
+  }
+  return true;
+}
+
+bool Builder::AddToolchainDep(BuilderRecord* record,
+                              const Target* target,
+                              Err* err) {
+  BuilderRecord* toolchain_record = GetOrCreateRecordOfType(
+      target->settings()->toolchain_label(), target->defined_from(),
+      BuilderRecord::ITEM_TOOLCHAIN, err);
+  if (!toolchain_record)
+    return false;
+  record->AddDep(toolchain_record);
+
+  return true;
+}
+
+void Builder::RecursiveSetShouldGenerate(BuilderRecord* record,
+                                         bool force) {
+  if (!force && record->should_generate())
+    return;  // Already set.
+  record->set_should_generate(true);
+
+  const BuilderRecordSet& deps = record->all_deps();
+  for (BuilderRecordSet::const_iterator i = deps.begin();
+       i != deps.end(); i++) {
+    BuilderRecord* cur = *i;
+    if (!cur->should_generate()) {
+      ScheduleItemLoadIfNecessary(cur);
+      RecursiveSetShouldGenerate(cur, false);
+    }
+  }
+}
+
+void Builder::ScheduleItemLoadIfNecessary(BuilderRecord* record) {
+  loader_->Load(record->label());
+}
+
+bool Builder::ResolveItem(BuilderRecord* record, Err* err) {
+  DCHECK(record->can_resolve() && !record->resolved());
+
+  if (record->type() == BuilderRecord::ITEM_TARGET) {
+    Target* target = record->item()->AsTarget();
+    if (!ResolveDeps(&target->deps(), err) ||
+        !ResolveDeps(&target->datadeps(), err) ||
+        !ResolveConfigs(&target->configs(), err) ||
+        !ResolveConfigs(&target->all_dependent_configs(), err) ||
+        !ResolveConfigs(&target->direct_dependent_configs(), err) ||
+        !ResolveForwardDependentConfigs(target, err))
+      return false;
+  }
+
+  record->set_resolved(true);
+  record->item()->OnResolved();
+  if (!resolved_callback_.is_null())
+    resolved_callback_.Run(record->item());
+
+  // Recursively update everybody waiting on this item to be resolved.
+  BuilderRecordSet& waiting_set = record->waiting_on_resolution();
+  for (BuilderRecordSet::iterator i = waiting_set.begin();
+       i != waiting_set.end(); ++i) {
+    BuilderRecord* waiting = *i;
+    DCHECK(waiting->unresolved_deps().find(record) !=
+           waiting->unresolved_deps().end());
+    waiting->unresolved_deps().erase(record);
+
+    if (waiting->can_resolve()) {
+      if (!ResolveItem(waiting, err))
+        return false;
+    }
+  }
+  waiting_set.clear();
+  return true;
+}
+
+bool Builder::ResolveDeps(LabelTargetVector* deps, Err* err) {
+  for (size_t i = 0; i < deps->size(); i++) {
+    LabelTargetPair& cur = (*deps)[i];
+    DCHECK(!cur.ptr);
+
+    BuilderRecord* record = GetResolvedRecordOfType(
+        cur.label, cur.origin, BuilderRecord::ITEM_TARGET, err);
+    if (!record)
+      return false;
+    cur.ptr = record->item()->AsTarget();
+  }
+  return true;
+}
+
+bool Builder::ResolveConfigs(LabelConfigVector* configs, Err* err) {
+  for (size_t i = 0; i < configs->size(); i++) {
+    LabelConfigPair& cur = (*configs)[i];
+    DCHECK(!cur.ptr);
+
+    BuilderRecord* record = GetResolvedRecordOfType(
+        cur.label, cur.origin, BuilderRecord::ITEM_CONFIG, err);
+    if (!record)
+      return false;
+    cur.ptr = record->item()->AsConfig();
+  }
+  return true;
+}
+
+// "Forward dependent configs" should refer to targets in the deps that should
+// have their configs forwarded.
+bool Builder::ResolveForwardDependentConfigs(Target* target, Err* err) {
+  const LabelTargetVector& deps = target->deps();
+  LabelTargetVector& configs = target->forward_dependent_configs();
+
+  // Assume that the lists are small so that brute-force n^2 is appropriate.
+  for (size_t config_i = 0; config_i < configs.size(); config_i++) {
+    for (size_t dep_i = 0; dep_i < deps.size(); dep_i++) {
+      if (configs[config_i].label == deps[dep_i].label) {
+        DCHECK(deps[dep_i].ptr);  // Should already be resolved.
+        configs[config_i].ptr = deps[dep_i].ptr;
+        break;
+      }
+    }
+    if (!configs[config_i].ptr) {
+      *err = Err(target->defined_from(),
+          "Target in forward_dependent_configs_from was not listed in the deps",
+          "The target \"" + configs[config_i].label.GetUserVisibleName(false) +
+          "\"\n was not present in the deps. This thing is used to forward\n"
+          "configs from direct dependents.");
+      return false;
+    }
+  }
+  return true;
+}
+
+std::string Builder::CheckForCircularDependencies(
+    const std::vector<const BuilderRecord*>& bad_records) const {
+  std::vector<const BuilderRecord*> cycle;
+  if (!RecursiveFindCycle(bad_records[0], &cycle))
+    return std::string();  // Didn't find a cycle, something else is wrong.
+
+  // Walk backwards since the dependency arrows point in the reverse direction.
+  std::string ret;
+  for (int i = static_cast<int>(cycle.size()) - 1; i >= 0; i--) {
+    ret += "  " + cycle[i]->label().GetUserVisibleName(false);
+    if (i != 0)
+      ret += " ->\n";
+  }
+
+  return ret;
+}
diff --git a/tools/gn/builder.h b/tools/gn/builder.h
new file mode 100644
index 0000000..994c8e1
--- /dev/null
+++ b/tools/gn/builder.h
@@ -0,0 +1,135 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TOOLS_GN_BUILDER_H_
+#define TOOLS_GN_BUILDER_H_
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "tools/gn/builder_record.h"
+#include "tools/gn/label.h"
+#include "tools/gn/label_ptr.h"
+
+class Config;
+class Err;
+class Loader;
+class ParseNode;
+
+class Builder : public base::RefCountedThreadSafe<Builder> {
+ public:
+  typedef base::Callback<void(const Item*)> ResolvedCallback;
+
+  Builder(Loader* loader);
+
+  // The resolved callback is called whenever a target has been resolved. This
+  // will be executed only on the main thread.
+  void set_resolved_callback(const ResolvedCallback& cb) {
+    resolved_callback_ = cb;
+  }
+
+  Loader* loader() const { return loader_; }
+
+  void ItemDefined(scoped_ptr<Item> item);
+
+  // Returns NULL if there is not a thing with the corresponding label.
+  const Item* GetItem(const Label& label) const;
+  const Toolchain* GetToolchain(const Label& label) const;
+
+  std::vector<const BuilderRecord*> GetAllRecords() const;
+
+  // Returns targets which should be generated and which are defined.
+  std::vector<const Target*> GetAllResolvedTargets() const;
+
+  // Returns the record for the given label, or NULL if it doesn't exist.
+  // Mostly used for unit tests.
+  const BuilderRecord* GetRecord(const Label& label) const;
+  BuilderRecord* GetRecord(const Label& label);
+
+  // If there are any undefined references, returns false and sets the error.
+  bool CheckForBadItems(Err* err) const;
+
+ private:
+  friend class base::RefCountedThreadSafe<Builder>;
+
+  virtual ~Builder();
+
+  bool TargetDefined(BuilderRecord* record, Err* err);
+
+  // Returns the record associated with the given label. This function checks
+  // that if we already have references for it, the type matches. If no record
+  // exists yet, a new one will be created.
+  //
+  // If any of the conditions fail, the return value will be null and the error
+  // will be set. request_from is used as the source of the error.
+  BuilderRecord* GetOrCreateRecordOfType(const Label& label,
+                                         const ParseNode* request_from,
+                                         BuilderRecord::ItemType type,
+                                         Err* err);
+
+  // Returns the record associated with the given label. This function checks
+  // that it's already been resolved to the correct type.
+  //
+  // If any of the conditions fail, the return value will be null and the error
+  // will be set. request_from is used as the source of the error.
+  BuilderRecord* GetResolvedRecordOfType(const Label& label,
+                                         const ParseNode* request_from,
+                                         BuilderRecord::ItemType type,
+                                         Err* err);
+
+  bool AddDeps(BuilderRecord* record,
+               const LabelConfigVector& configs,
+               Err* err);
+  bool AddDeps(BuilderRecord* record,
+               const LabelTargetVector& targets,
+               Err* err);
+  bool AddToolchainDep(BuilderRecord* record,
+                       const Target* target,
+                       Err* err);
+
+  // Given a target, sets the "should generate" bit and pushes it through the
+  // dependency tree. Any time the bit it set, we ensure that the given item is
+  // scheduled to be loaded.
+  //
+  // If the force flag is set, we'll ignore the current state of the record's
+  // should_generate flag, and set it on the dependents every time. This is
+  // used when defining a target: the "should generate" may have been set
+  // before the item was defined (if it is required by something that is
+  // required). In this case, we need to re-push the "should generate" flag
+  // to the item's dependencies.
+  void RecursiveSetShouldGenerate(BuilderRecord* record, bool force);
+
+  void ScheduleItemLoadIfNecessary(BuilderRecord* record);
+
+  // This takes a BuilderRecord with resolved depdencies, and fills in the
+  // target's Label*Vectors with the resolved pointers.
+  bool ResolveItem(BuilderRecord* record, Err* err);
+
+  // Fills in the pointers in the given vector based on the labels. We assume
+  // that everything should be resolved by this point, so will return an error
+  // if anything isn't found or if the type doesn't match.
+  bool ResolveDeps(LabelTargetVector* deps, Err* err);
+  bool ResolveConfigs(LabelConfigVector* configs, Err* err);
+  bool ResolveForwardDependentConfigs(Target* target, Err* err);
+
+  // Given a list of unresolved records, tries to find any circular
+  // dependencies and returns the string describing the problem. If no circular
+  // deps were found, returns the empty string.
+  std::string CheckForCircularDependencies(
+      const std::vector<const BuilderRecord*>& bad_records) const;
+
+  // Non owning pointer.
+  Loader* loader_;
+
+  // Owning pointers.
+  typedef base::hash_map<Label, BuilderRecord*> RecordMap;
+  RecordMap records_;
+
+  ResolvedCallback resolved_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(Builder);
+};
+
+#endif  // TOOLS_GN_BUILDER_H_
diff --git a/tools/gn/builder_record.cc b/tools/gn/builder_record.cc
new file mode 100644
index 0000000..066b1ea
--- /dev/null
+++ b/tools/gn/builder_record.cc
@@ -0,0 +1,69 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "tools/gn/builder_record.h"
+
+#include "tools/gn/item.h"
+
+BuilderRecord::BuilderRecord(ItemType type, const Label& label)
+    : type_(type),
+      label_(label),
+      originally_referenced_from_(NULL),
+      should_generate_(false),
+      resolved_(false) {
+}
+
+BuilderRecord::~BuilderRecord() {
+}
+
+// static
+const char* BuilderRecord::GetNameForType(ItemType type) {
+  switch (type) {
+    case ITEM_TARGET:
+      return "target";
+    case ITEM_CONFIG:
+      return "config";
+    case ITEM_TOOLCHAIN:
+      return "toolchain";
+    case ITEM_UNKNOWN:
+    default:
+      return "unknown";
+  }
+}
+
+// static
+bool BuilderRecord::IsItemOfType(const Item* item, ItemType type) {
+  switch (type) {
+    case ITEM_TARGET:
+      return !!item->AsTarget();
+    case ITEM_CONFIG:
+      return !!item->AsConfig();
+    case ITEM_TOOLCHAIN:
+      return !!item->AsToolchain();
+    case ITEM_UNKNOWN:
+    default:
+      return false;
+  }
+}
+
+// static
+BuilderRecord::ItemType BuilderRecord::TypeOfItem(const Item* item) {
+  if (item->AsTarget())
+    return ITEM_TARGET;
+  if (item->AsConfig())
+    return ITEM_CONFIG;
+  if (item->AsToolchain())
+    return ITEM_TOOLCHAIN;
+
+  NOTREACHED();
+  return ITEM_UNKNOWN;
+}
+
+void BuilderRecord::AddDep(BuilderRecord* record) {
+  all_deps_.insert(record);
+  if (!record->resolved()) {
+    unresolved_deps_.insert(record);
+    record->waiting_on_resolution_.insert(this);
+  }
+}
diff --git a/tools/gn/builder_record.h b/tools/gn/builder_record.h
new file mode 100644
index 0000000..6e7e9bb
--- /dev/null
+++ b/tools/gn/builder_record.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TOOLS_GN_BUILDER_RECORD_H_
+#define TOOLS_GN_BUILDER_RECORD_H_
+
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "tools/gn/item.h"
+#include "tools/gn/location.h"
+
+class ParseNode;
+
+// This class is used by the builder to manage the loading of the dependency
+// tree. It holds a reference to an item and links to other records that the
+// item depends on, both resolved ones, and unresolved ones.
+//
+// If a target depends on another one that hasn't been defined yet, we'll make
+// a placeholder BuilderRecord with no item, and try to load the buildfile
+// associated with the new item. The item will get filled in when we encounter
+// the declaration for the item (or when we're done and realize there are
+// undefined items).
+//
+// You can also have null item pointers when the target is not required for
+// the current build (should_generate is false).
+class BuilderRecord {
+ public:
+  typedef std::set<BuilderRecord*> BuilderRecordSet;
+
+  enum ItemType {
+    ITEM_UNKNOWN,
+    ITEM_TARGET,
+    ITEM_CONFIG,
+    ITEM_TOOLCHAIN
+  };
+
+  //BuilderRecord();
+  BuilderRecord(ItemType type, const Label& label);
+  ~BuilderRecord();
+
+  ItemType type() const { return type_; }
+  const Label& label() const { return label_; }
+
+  // Returns a user-ready name for the given type. e.g. "target".
+  static const char* GetNameForType(ItemType type);
+
+  // Returns true if the given item is of the given type.
+  static bool IsItemOfType(const Item* item, ItemType type);
+
+  // Returns the type enum for the given item.
+  static ItemType TypeOfItem(const Item* item);
+
+  Item* item() { return item_.get(); }
+  const Item* item() const { return item_.get(); }
+  void set_item(scoped_ptr<Item> item) { item_ = item.Pass(); }
+
+  // Indicates from where this item was originally referenced from that caused
+  // it to be loaded. For targets for which we encountered the declaration
+  // before a reference, this will be the empty range.
+  const ParseNode* originally_referenced_from() const {
+    return originally_referenced_from_;
+  }
+  void set_originally_referenced_from(const ParseNode* pn) {
+    originally_referenced_from_ = pn;
+  }
+
+  bool should_generate() const { return should_generate_; }
+  void set_should_generate(bool sg) { should_generate_ = sg; }
+
+  bool resolved() const { return resolved_; }
+  void set_resolved(bool r) { resolved_ = r; }
+
+  bool can_resolve() const {
+    return item_ && unresolved_deps_.empty();
+  }
+
+  // All records this one is depending on.
+  BuilderRecordSet& all_deps() { return all_deps_; }
+  const BuilderRecordSet& all_deps() const { return all_deps_; }
+
+  // Unresolved records this one is depending on. A subset of all... above.
+  BuilderRecordSet& unresolved_deps() { return unresolved_deps_; }
+  const BuilderRecordSet& unresolved_deps() const { return unresolved_deps_; }
+
+  // Records that are waiting on this one to be resolved. This is the other
+  // end of the "unresolved deps" arrow.
+  BuilderRecordSet& waiting_on_resolution() { return waiting_on_resolution_; }
+  const BuilderRecordSet& waiting_on_resolution() const {
+    return waiting_on_resolution_;
+  }
+
+  void AddDep(BuilderRecord* record);
+
+ private:
+  ItemType type_;
+  Label label_;
+  scoped_ptr<Item> item_;
+  const ParseNode* originally_referenced_from_;
+  bool should_generate_;
+  bool resolved_;
+
+  BuilderRecordSet all_deps_;
+  BuilderRecordSet unresolved_deps_;
+  BuilderRecordSet waiting_on_resolution_;
+
+  DISALLOW_COPY_AND_ASSIGN(BuilderRecord);
+};
+
+#endif  // TOOLS_GN_BUILDER_RECORD_H_
diff --git a/tools/gn/builder_unittest.cc b/tools/gn/builder_unittest.cc
new file mode 100644
index 0000000..538d5f5
--- /dev/null
+++ b/tools/gn/builder_unittest.cc
@@ -0,0 +1,226 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "tools/gn/builder.h"
+#include "tools/gn/loader.h"
+#include "tools/gn/target.h"
+#include "tools/gn/test_with_scope.h"
+#include "tools/gn/toolchain.h"
+
+namespace {
+
+class MockLoader : public Loader {
+ public:
+  MockLoader() {
+  }
+
+  // Loader implementation:
+  virtual void Load(const SourceFile& file,
+                    const Label& toolchain_name) OVERRIDE {
+    files_.push_back(file);
+  }
+  virtual void ToolchainLoaded(const Toolchain* toolchain) OVERRIDE {
+  }
+  virtual Label GetDefaultToolchain() const OVERRIDE {
+    return Label();
+  }
+  virtual const Settings* GetToolchainSettings(const Label& label) OVERRIDE {
+    return NULL;
+  }
+
+  bool HasLoadedNone() const {
+    return files_.empty();
+  }
+
+  // Returns true if one load has been requested and it matches the given
+  // file. This will clear the records so it will be empty for the next call.
+  bool HasLoadedOne(const SourceFile& f) {
+    if (files_.size() != 1u) {
+      files_.clear();
+      return false;
+    }
+
+    bool match = (files_[0] == f);
+    files_.clear();
+    return match;
+  }
+
+  // Like HasLoadedOne above. Accepts any ordering.
+  bool HasLoadedTwo(const SourceFile& a, const SourceFile& b) {
+    if (files_.size() != 2u) {
+      files_.clear();
+      return false;
+    }
+
+    bool match = (
+        (files_[0] == a && files_[1] == b) ||
+        (files_[0] == b && files_[0] == a));
+    files_.clear();
+    return match;
+  }
+
+ private:
+  virtual ~MockLoader() {}
+
+  std::vector<SourceFile> files_;
+};
+
+class BuilderTest : public testing::Test {
+ public:
+  BuilderTest()
+      : loader_(new MockLoader),
+        builder_(new Builder(loader_.get())),
+        settings_(&build_settings_, std::string()),
+        scope_(&settings_) {
+    build_settings_.SetBuildDir(SourceDir("//out/"));
+    settings_.set_toolchain_label(Label(SourceDir("//tc/"), "default"));
+    settings_.set_default_toolchain_label(settings_.toolchain_label());
+  }
+
+  Toolchain* DefineToolchain() {
+    Toolchain* tc = new Toolchain(&settings_, settings_.toolchain_label());
+    builder_->ItemDefined(scoped_ptr<Item>(tc));
+    return tc;
+  }
+
+ protected:
+  scoped_refptr<MockLoader> loader_;
+  scoped_refptr<Builder> builder_;
+  BuildSettings build_settings_;
+  Settings settings_;
+  Scope scope_;
+};
+
+}  // namespace
+
+TEST_F(BuilderTest, BasicDeps) {
+  SourceDir toolchain_dir = settings_.toolchain_label().dir();
+  std::string toolchain_name = settings_.toolchain_label().name();
+
+  DefineToolchain();
+  BuilderRecord* toolchain_record =
+      builder_->GetRecord(settings_.toolchain_label());
+  ASSERT_TRUE(toolchain_record);
+  EXPECT_EQ(BuilderRecord::ITEM_TOOLCHAIN, toolchain_record->type());
+
+  // Construct a dependency chain: A -> B -> C. Define A first with a
+  // forward-reference to B, then C, then B to test the different orders that
+  // the dependencies are hooked up.
+  Label a_label(SourceDir("//a/"), "a", toolchain_dir, toolchain_name);
+  Label b_label(SourceDir("//b/"), "b", toolchain_dir, toolchain_name);
+  Label c_label(SourceDir("//c/"), "c", toolchain_dir, toolchain_name);
+
+  // The builder will take ownership of the pointers.
+  Target* a = new Target(&settings_, a_label);
+  a->deps().push_back(LabelTargetPair(b_label));
+  a->set_output_type(Target::EXECUTABLE);
+  builder_->ItemDefined(scoped_ptr<Item>(a));
+
+  // Should have requested that B and the toolchain is loaded.
+  EXPECT_TRUE(loader_->HasLoadedTwo(SourceFile("//tc/BUILD.gn"),
+                                    SourceFile("//b/BUILD.gn")));
+
+  // A should be unresolved with an item
+  BuilderRecord* a_record = builder_->GetRecord(a_label);
+  EXPECT_TRUE(a_record->item());
+  EXPECT_FALSE(a_record->resolved());
+  EXPECT_FALSE(a_record->can_resolve());
+
+  // B should be unresolved, have no item, and no deps.
+  BuilderRecord* b_record = builder_->GetRecord(b_label);
+  EXPECT_FALSE(b_record->item());
+  EXPECT_FALSE(b_record->resolved());
+  EXPECT_FALSE(b_record->can_resolve());
+  EXPECT_TRUE(b_record->all_deps().empty());
+
+  // A should have two deps: B and the toolchain. Only B should be unresolved.
+  EXPECT_EQ(2u, a_record->all_deps().size());
+  EXPECT_EQ(1u, a_record->unresolved_deps().size());
+  EXPECT_NE(a_record->all_deps().end(),
+            a_record->all_deps().find(toolchain_record));
+  EXPECT_NE(a_record->all_deps().end(),
+            a_record->all_deps().find(b_record));
+  EXPECT_NE(a_record->unresolved_deps().end(),
+            a_record->unresolved_deps().find(b_record));
+
+  // B should be marked as having A waiting on it.
+  EXPECT_EQ(1u, b_record->waiting_on_resolution().size());
+  EXPECT_NE(b_record->waiting_on_resolution().end(),
+            b_record->waiting_on_resolution().find(a_record));
+
+  // Add the C target.
+  Target* c = new Target(&settings_, c_label);
+  c->set_output_type(Target::STATIC_LIBRARY);
+  builder_->ItemDefined(scoped_ptr<Item>(c));
+
+  // C only depends on the already-loaded toolchain so we shouldn't have
+  // requested anything else.
+  EXPECT_TRUE(loader_->HasLoadedNone());
+
+  // Add the B target.
+  Target* b = new Target(&settings_, b_label);
+  a->deps().push_back(LabelTargetPair(c_label));
+  b->set_output_type(Target::SHARED_LIBRARY);
+  builder_->ItemDefined(scoped_ptr<Item>(b));
+
+  // B depends only on the already-loaded C and toolchain so we shouldn't have
+  // requested anything else.
+  EXPECT_TRUE(loader_->HasLoadedNone());
+
+  // All targets should now be resolved.
+  BuilderRecord* c_record = builder_->GetRecord(c_label);
+  EXPECT_TRUE(a_record->resolved());
+  EXPECT_TRUE(b_record->resolved());
+  EXPECT_TRUE(c_record->resolved());
+
+  EXPECT_TRUE(a_record->unresolved_deps().empty());
+  EXPECT_TRUE(b_record->unresolved_deps().empty());
+  EXPECT_TRUE(c_record->unresolved_deps().empty());
+
+  EXPECT_TRUE(a_record->waiting_on_resolution().empty());
+  EXPECT_TRUE(b_record->waiting_on_resolution().empty());
+  EXPECT_TRUE(c_record->waiting_on_resolution().empty());
+}
+
+// Tests that the should generate bit is set and propogated properly.
+TEST_F(BuilderTest, ShouldGenerate) {
+  DefineToolchain();
+
+  // Define a secondary toolchain.
+  Settings settings2(&build_settings_, "secondary");
+  Label toolchain_label2(SourceDir("//tc/"), "secondary");
+  settings2.set_toolchain_label(toolchain_label2);
+  Toolchain* tc2 = new Toolchain(&settings2, toolchain_label2);
+  builder_->ItemDefined(scoped_ptr<Item>(tc2));
+
+  // Construct a dependency chain: A -> B. A is in the default toolchain, B
+  // is not.
+  Label a_label(SourceDir("//foo/"), "a",
+                settings_.toolchain_label().dir(), "a");
+  Label b_label(SourceDir("//foo/"), "b",
+                toolchain_label2.dir(), toolchain_label2.name());
+
+  // First define B.
+  Target* b = new Target(&settings2, b_label);
+  b->set_output_type(Target::EXECUTABLE);
+  builder_->ItemDefined(scoped_ptr<Item>(b));
+
+  // B should not be marked generated by default.
+  BuilderRecord* b_record = builder_->GetRecord(b_label);
+  EXPECT_FALSE(b_record->should_generate());
+
+  // Define A with a dependency on B.
+  Target* a = new Target(&settings_, a_label);
+  a->deps().push_back(LabelTargetPair(b_label));
+  a->set_output_type(Target::EXECUTABLE);
+  builder_->ItemDefined(scoped_ptr<Item>(a));
+
+  // A should have the generate bit set since it's in the default toolchain.
+  BuilderRecord* a_record = builder_->GetRecord(a_label);
+  EXPECT_TRUE(a_record->should_generate());
+
+  // It should have gotten pushed to B.
+  EXPECT_TRUE(b_record->should_generate());
+}
diff --git a/tools/gn/command_desc.cc b/tools/gn/command_desc.cc
index 415666c..f680da3 100644
--- a/tools/gn/command_desc.cc
+++ b/tools/gn/command_desc.cc
@@ -10,8 +10,8 @@
 #include "tools/gn/commands.h"
 #include "tools/gn/config.h"
 #include "tools/gn/config_values_extractors.h"
+#include "tools/gn/filesystem_utils.h"
 #include "tools/gn/item.h"
-#include "tools/gn/item_node.h"
 #include "tools/gn/label.h"
 #include "tools/gn/setup.h"
 #include "tools/gn/standard_out.h"
@@ -21,6 +21,23 @@
 
 namespace {
 
+// Prints the given directory in a nice way for the user to view.
+std::string FormatSourceDir(const SourceDir& dir) {
+#if defined(OS_WIN)
+  // On Windows we fix up system absolute paths to look like native ones.
+  // Internally, they'll look like "/C:\foo\bar/"
+  if (dir.is_system_absolute()) {
+    std::string buf = dir.value();
+    if (buf.size() > 3 && buf[2] == ':') {
+      buf.erase(buf.begin());  // Erase beginning slash.
+      ConvertPathToSystem(&buf);  // Convert to backslashes.
+      return buf;
+    }
+  }
+#endif
+  return dir.value();
+}
+
 void RecursiveCollectChildDeps(const Target* target, std::set<Label>* result);
 
 void RecursiveCollectDeps(const Target* target, std::set<Label>* result) {
@@ -114,7 +131,7 @@
     OutputString("\nlib_dirs\n");
 
   for (size_t i = 0; i < lib_dirs.size(); i++)
-    OutputString("    " + lib_dirs[i].value() + "\n");
+    OutputString("    " + FormatSourceDir(lib_dirs[i]) + "\n");
 }
 
 void PrintLibs(const Target* target, bool display_header) {
@@ -176,7 +193,7 @@
 };
 template<> struct DescValueWriter<SourceDir> {
   void operator()(const SourceDir& dir, std::ostream& out) const {
-    out << "    " << dir.value() << "\n";
+    out << "    " << FormatSourceDir(dir) << "\n";
   }
 };
 
diff --git a/tools/gn/command_gen.cc b/tools/gn/command_gen.cc
index 9f6d38f..cde677a 100644
--- a/tools/gn/command_gen.cc
+++ b/tools/gn/command_gen.cc
@@ -22,10 +22,26 @@
 // Suppress output on success.
 const char kSwitchQuiet[] = "q";
 
-void TargetResolvedCallback(base::subtle::Atomic32* write_counter,
-                            const Target* target) {
+void BackgroundDoWrite(const Target* target, const Toolchain* toolchain) {
+  NinjaTargetWriter::RunAndWriteFile(target, toolchain);
+  g_scheduler->DecrementWorkCount();
+}
+
+// Called on the main thread.
+void ItemResolvedCallback(base::subtle::Atomic32* write_counter,
+                          scoped_refptr<Builder> builder,
+                          const Item* item) {
   base::subtle::NoBarrier_AtomicIncrement(write_counter, 1);
-  NinjaTargetWriter::RunAndWriteFile(target);
+
+  const Target* target = item->AsTarget();
+  if (target) {
+    const Toolchain* toolchain =
+        builder->GetToolchain(target->settings()->toolchain_label());
+    DCHECK(toolchain);
+    g_scheduler->IncrementWorkCount();
+    g_scheduler->ScheduleWork(
+        base::Bind(&BackgroundDoWrite, target, toolchain));
+  }
 }
 
 }  // namespace
@@ -51,15 +67,17 @@
   // Cause the load to also generate the ninja files for each target. We wrap
   // the writing to maintain a counter.
   base::subtle::Atomic32 write_counter = 0;
-  setup->build_settings().set_target_resolved_callback(
-      base::Bind(&TargetResolvedCallback, &write_counter));
+  setup->builder()->set_resolved_callback(
+      base::Bind(&ItemResolvedCallback, &write_counter,
+                 scoped_refptr<Builder>(setup->builder())));
 
   // Do the actual load. This will also write out the target ninja files.
   if (!setup->Run())
     return 1;
 
   // Write the root ninja files.
-  if (!NinjaWriter::RunAndWriteFiles(&setup->build_settings()))
+  if (!NinjaWriter::RunAndWriteFiles(&setup->build_settings(),
+                                     setup->builder()))
     return 1;
 
   base::TimeTicks end_time = base::TimeTicks::Now();
diff --git a/tools/gn/command_gyp.cc b/tools/gn/command_gyp.cc
index 0aff1a9..06e5bde 100644
--- a/tools/gn/command_gyp.cc
+++ b/tools/gn/command_gyp.cc
@@ -16,7 +16,6 @@
 #include "tools/gn/err.h"
 #include "tools/gn/gyp_helper.h"
 #include "tools/gn/gyp_target_writer.h"
-#include "tools/gn/item_node.h"
 #include "tools/gn/location.h"
 #include "tools/gn/setup.h"
 #include "tools/gn/source_file.h"
@@ -32,17 +31,31 @@
 typedef std::map<SourceFile, std::vector<TargetGroup> > GroupedTargetsMap;
 typedef std::map<std::string, std::string> StringStringMap;
 
+std::vector<const BuilderRecord*> GetAllResolvedTargetRecords(
+    const Builder* builder) {
+  std::vector<const BuilderRecord*> all = builder->GetAllRecords();
+  std::vector<const BuilderRecord*> result;
+  result.reserve(all.size());
+  for (size_t i = 0; i < all.size(); i++) {
+    if (all[i]->type() == BuilderRecord::ITEM_TARGET &&
+        all[i]->should_generate() &&
+        all[i]->item())
+      result.push_back(all[i]);
+  }
+  return result;
+}
+
 // Groups targets sharing the same label between debug and release.
-void CorrelateTargets(const std::vector<const Target*>& debug_targets,
-                      const std::vector<const Target*>& release_targets,
+void CorrelateTargets(const std::vector<const BuilderRecord*>& debug_targets,
+                      const std::vector<const BuilderRecord*>& release_targets,
                       CorrelatedTargetsMap* correlated) {
   for (size_t i = 0; i < debug_targets.size(); i++) {
-    const Target* target = debug_targets[i];
-    (*correlated)[target->label()].debug = target;
+    const BuilderRecord* record = debug_targets[i];
+    (*correlated)[record->label()].debug = record;
   }
   for (size_t i = 0; i < release_targets.size(); i++) {
-    const Target* target = release_targets[i];
-    (*correlated)[target->label()].release = target;
+    const BuilderRecord* record = release_targets[i];
+    (*correlated)[record->label()].release = record;
   }
 }
 
@@ -51,18 +64,21 @@
 bool EnsureTargetsMatch(const TargetGroup& group, Err* err) {
   // Check that both debug and release made this target.
   if (!group.debug || !group.release) {
-    const Target* non_null_one = group.debug ? group.debug : group.release;
+    const BuilderRecord* non_null_one =
+        group.debug ? group.debug : group.release;
     *err = Err(Location(), "The debug and release builds did not both generate "
         "a target with the name\n" +
         non_null_one->label().GetUserVisibleName(true));
     return false;
   }
 
+  const Target* debug_target = group.debug->item()->AsTarget();
+  const Target* release_target = group.release->item()->AsTarget();
+
   // Check the flags that determine if and where we write the GYP file.
-  if (group.debug->item_node()->should_generate() !=
-          group.release->item_node()->should_generate() ||
-      group.debug->external() != group.release->external() ||
-      group.debug->gyp_file() != group.release->gyp_file()) {
+  if (group.debug->should_generate() != group.release->should_generate() ||
+      debug_target->external() != release_target->external() ||
+      debug_target->gyp_file() != release_target->gyp_file()) {
     *err = Err(Location(), "The metadata for the target\n" +
         group.debug->label().GetUserVisibleName(true) +
         "\ndoesn't match between the debug and release builds.");
@@ -70,41 +86,40 @@
   }
 
   // Check that the sources match.
-  if (group.debug->sources().size() != group.release->sources().size()) {
+  if (debug_target->sources().size() != release_target->sources().size()) {
     *err = Err(Location(), "The source file count for the target\n" +
         group.debug->label().GetUserVisibleName(true) +
         "\ndoesn't have the same number of files between the debug and "
         "release builds.");
     return false;
   }
-  for (size_t i = 0; i < group.debug->sources().size(); i++) {
-    if (group.debug->sources()[i] != group.release->sources()[i]) {
+  for (size_t i = 0; i < debug_target->sources().size(); i++) {
+    if (debug_target->sources()[i] != release_target->sources()[i]) {
       *err = Err(Location(), "The debug and release version of the target \n" +
           group.debug->label().GetUserVisibleName(true) +
           "\ndon't agree on the file\n" +
-          group.debug->sources()[i].value());
+          debug_target->sources()[i].value());
       return false;
     }
   }
 
   // Check that the deps match.
-  if (group.debug->deps().size() != group.release->deps().size()) {
+  if (debug_target->deps().size() != release_target->deps().size()) {
     *err = Err(Location(), "The source file count for the target\n" +
         group.debug->label().GetUserVisibleName(true) +
         "\ndoesn't have the same number of deps between the debug and "
         "release builds.");
     return false;
   }
-  for (size_t i = 0; i < group.debug->deps().size(); i++) {
-    if (group.debug->deps()[i].label != group.release->deps()[i].label) {
+  for (size_t i = 0; i < debug_target->deps().size(); i++) {
+    if (debug_target->deps()[i].label != release_target->deps()[i].label) {
       *err = Err(Location(), "The debug and release version of the target \n" +
           group.debug->label().GetUserVisibleName(true) +
           "\ndon't agree on the dep\n" +
-          group.debug->deps()[i].label.GetUserVisibleName(true));
+          debug_target->deps()[i].label.GetUserVisibleName(true));
       return false;
     }
   }
-
   return true;
 }
 
@@ -212,16 +227,15 @@
   return result;
 }
 
-// Returns the number of targets, number of GYP files.
-std::pair<int, int> WriteGypFiles(
-    const BuildSettings& debug_settings,
-    const BuildSettings& release_settings,
-    Err* err) {
+// Returns the (number of targets, number of GYP files).
+std::pair<int, int> WriteGypFiles(CommonSetup* debug_setup,
+                                  CommonSetup* release_setup,
+                                  Err* err) {
   // Group all targets by output GYP file name.
-  std::vector<const Target*> debug_targets;
-  std::vector<const Target*> release_targets;
-  debug_settings.target_manager().GetAllTargets(&debug_targets);
-  release_settings.target_manager().GetAllTargets(&release_targets);
+  std::vector<const BuilderRecord*> debug_targets =
+      GetAllResolvedTargetRecords(debug_setup->builder());
+  std::vector<const BuilderRecord*> release_targets =
+      GetAllResolvedTargetRecords(release_setup->builder());
 
   // Match up the debug and release version of each target by label.
   CorrelatedTargetsMap correlated;
@@ -233,19 +247,20 @@
   for (CorrelatedTargetsMap::iterator i = correlated.begin();
        i != correlated.end(); ++i) {
     const TargetGroup& group = i->second;
-    if (!group.debug->item_node()->should_generate())
+    if (!group.debug->should_generate())
       continue;  // Skip non-generated ones.
-    if (group.debug->external())
+    if (group.debug->item()->AsTarget()->external())
       continue;  // Skip external ones.
-    if (group.debug->gyp_file().is_null())
+    if (group.debug->item()->AsTarget()->gyp_file().is_null())
       continue;  // Skip ones without GYP files.
 
     if (!EnsureTargetsMatch(group, err))
       return std::make_pair(0, 0);
 
     target_count++;
-    grouped_targets[helper.GetGypFileForTarget(group.debug, err)].push_back(
-        group);
+    grouped_targets[
+            helper.GetGypFileForTarget(group.debug->item()->AsTarget(), err)]
+        .push_back(group);
     if (err->has_error())
       return std::make_pair(0, 0);
   }
@@ -358,9 +373,7 @@
     return 1;
 
   Err err;
-  std::pair<int, int> counts = WriteGypFiles(setup_debug->build_settings(),
-                                             setup_release->build_settings(),
-                                             &err);
+  std::pair<int, int> counts = WriteGypFiles(setup_debug, setup_release, &err);
   if (err.has_error()) {
     err.PrintToStdout();
     return 1;
diff --git a/tools/gn/command_refs.cc b/tools/gn/command_refs.cc
index d49f536..fde617c 100644
--- a/tools/gn/command_refs.cc
+++ b/tools/gn/command_refs.cc
@@ -9,7 +9,6 @@
 #include "tools/gn/filesystem_utils.h"
 #include "tools/gn/input_file.h"
 #include "tools/gn/item.h"
-#include "tools/gn/item_node.h"
 #include "tools/gn/pattern.h"
 #include "tools/gn/setup.h"
 #include "tools/gn/standard_out.h"
@@ -19,12 +18,12 @@
 
 namespace {
 
-// Returns the file path generating this item node.
-base::FilePath FilePathForItemNode(const ItemNode& node) {
-  const InputFile* file = node.generated_from_here().begin().file();
-  if (!file)
+// Returns the file path generating this record.
+base::FilePath FilePathForRecord(const BuilderRecord* record) {
+  if (!record->item())
     return base::FilePath(FILE_PATH_LITERAL("=UNRESOLVED DEPENDENCY="));
-  return file->physical_name();
+  return record->item()->defined_from()->GetRange().begin().file()
+      ->physical_name();
 }
 
 }  // namespace
@@ -34,6 +33,7 @@
     "refs: Find stuff referencing a target, directory, or config.";
 const char kRefs_Help[] =
     "gn refs <label_pattern> [--files]\n"
+    "\n"
     "  Finds code referencing a given label. The label can be a\n"
     "  target or config name. Unlike most other commands, unresolved\n"
     "  dependencies will be tolerated. This allows you to use this command\n"
@@ -88,33 +88,30 @@
   if (!setup->DoSetup() || !setup->Run())
     return 1;
 
-  const ItemTree& item_tree = setup->build_settings().item_tree();
-  base::AutoLock lock(item_tree.lock());
-
-  std::vector<const ItemNode*> nodes;
-  item_tree.GetAllItemNodesLocked(&nodes);
+  std::vector<const BuilderRecord*> records = setup->builder()->GetAllRecords();
 
   const CommandLine* cmdline = CommandLine::ForCurrentProcess();
 
   bool file_output = cmdline->HasSwitch("files");
   std::set<std::string> unique_output;
 
-  for (size_t node_index = 0; node_index < nodes.size(); node_index++) {
-    const ItemNode& node = *nodes[node_index];
-    const ItemNode::ItemNodeMap& deps = node.direct_dependencies();
-    for (ItemNode::ItemNodeMap::const_iterator d = deps.begin();
+  for (size_t record_index = 0; record_index < records.size(); record_index++) {
+    const BuilderRecord* record = records[record_index];
+    const BuilderRecord::BuilderRecordSet& deps = record->all_deps();
+    for (BuilderRecord::BuilderRecordSet::const_iterator d = deps.begin();
          d != deps.end(); ++d) {
-      std::string label = d->first->item()->label().GetUserVisibleName(false);
+      std::string label = (*d)->label().GetUserVisibleName(false);
       if (pattern.MatchesString(label)) {
         // Got a match.
         if (file_output) {
-          unique_output.insert(FilePathToUTF8(FilePathForItemNode(node)));
+          unique_output.insert(FilePathToUTF8(FilePathForRecord(record)));
           break;  // Found a match for this target's file, don't need more.
         } else {
           // We can get dupes when there are differnet toolchains involved,
           // so we want to send all output through the de-duper.
           unique_output.insert(
-              node.item()->label().GetUserVisibleName(false) + " -> " + label);
+              record->item()->label().GetUserVisibleName(false) + " -> " +
+              label);
         }
       }
     }
diff --git a/tools/gn/commands.cc b/tools/gn/commands.cc
index e600872..d40beab 100644
--- a/tools/gn/commands.cc
+++ b/tools/gn/commands.cc
@@ -4,7 +4,6 @@
 
 #include "tools/gn/commands.h"
 #include "tools/gn/item.h"
-#include "tools/gn/item_node.h"
 #include "tools/gn/label.h"
 #include "tools/gn/setup.h"
 #include "tools/gn/standard_out.h"
@@ -52,7 +51,7 @@
   if (!setup->DoSetup())
     return NULL;
 
-  // FIXME(brettw): set the output dir to be a sandbox one to avoid polluting
+  // TODO(brettw): set the output dir to be a sandbox one to avoid polluting
   // the real output dir with files written by the build scripts.
 
   // Do the actual load. This will also write out the target ninja files.
@@ -62,8 +61,7 @@
   // Need to resolve the label after we know the default toolchain.
   // TODO(brettw) find the current directory and resolve the input label
   // relative to that.
-  Label default_toolchain = setup->build_settings().toolchain_manager()
-      .GetDefaultToolchainUnlocked();
+  Label default_toolchain = setup->loader()->default_toolchain_label();
   Value arg_value(NULL, args[0]);
   Err err;
   Label label =
@@ -73,19 +71,14 @@
     return NULL;
   }
 
-  ItemNode* node;
-  {
-    base::AutoLock lock(setup->build_settings().item_tree().lock());
-    node = setup->build_settings().item_tree().GetExistingNodeLocked(label);
-  }
-  if (!node) {
-    Err(Location(), "",
-        "I don't know about this \"" + label.GetUserVisibleName(false) +
-        "\"").PrintToStdout();
+  const Item* item = setup->builder()->GetItem(label);
+  if (!item) {
+    Err(Location(), "Label not found.",
+        label.GetUserVisibleName(false) + " not found.").PrintToStdout();
     return NULL;
   }
 
-  const Target* target = node->item()->AsTarget();
+  const Target* target = item->AsTarget();
   if (!target) {
     Err(Location(), "Not a target.",
         "The \"" + label.GetUserVisibleName(false) + "\" thing\n"
diff --git a/tools/gn/config.cc b/tools/gn/config.cc
index 5b89e2b..dce951f 100644
--- a/tools/gn/config.cc
+++ b/tools/gn/config.cc
@@ -6,8 +6,6 @@
 
 #include "tools/gn/err.h"
 #include "tools/gn/input_file_manager.h"
-#include "tools/gn/item_node.h"
-#include "tools/gn/item_tree.h"
 #include "tools/gn/scheduler.h"
 
 Config::Config(const Settings* settings, const Label& label)
@@ -24,59 +22,3 @@
 const Config* Config::AsConfig() const {
   return this;
 }
-
-// static
-Config* Config::GetConfig(const Settings* settings,
-                          const LocationRange& specified_from_here,
-                          const Label& label,
-                          Item* dep_from,
-                          Err* err) {
-  DCHECK(!label.is_null());
-
-  ItemTree* tree = &settings->build_settings()->item_tree();
-  base::AutoLock lock(tree->lock());
-
-  ItemNode* node = tree->GetExistingNodeLocked(label);
-  Config* config = NULL;
-  if (!node) {
-    config = new Config(settings, label);
-    node = new ItemNode(config);
-    node->set_originally_referenced_from_here(specified_from_here);
-    tree->AddNodeLocked(node);
-
-    // Only schedule loading the given target if somebody is depending on it
-    // (and we optimize by not re-asking it to run the current file).
-    // Otherwise, we're probably generating it right now.
-    if (dep_from && dep_from->label().dir() != label.dir()) {
-      settings->build_settings()->toolchain_manager().ScheduleInvocationLocked(
-          specified_from_here, label.GetToolchainLabel(), label.dir(),
-          err);
-    }
-  } else if ((config = node->item()->AsConfig())) {
-    // Previously saw this item as a config.
-
-    // If we have no dep_from, we're generating it. In this case, it had better
-    // not already be generated.
-    if (!dep_from && node->state() != ItemNode::REFERENCED) {
-      *err = Err(specified_from_here, "Duplicate config definition.",
-          "You already told me about a config with this name.");
-      return NULL;
-    }
-  } else {
-    // Previously saw this thing as a non-config.
-    *err = Err(specified_from_here,
-               "Config name already used.",
-               "Previously you specified a " +
-               node->item()->GetItemTypeName() + " with this name instead.");
-    return NULL;
-  }
-
-  // Keep a record of the guy asking us for this dependency. We know if
-  // somebody is adding a dependency, that guy it himself not resolved.
-  if (dep_from) {
-    if (!dep_from->item_node()->AddDependency(
-            settings->build_settings(), specified_from_here, node, err))
-      return NULL;
-  }
-  return config;
-}
diff --git a/tools/gn/config.h b/tools/gn/config.h
index e5a1df6..f08b859 100644
--- a/tools/gn/config.h
+++ b/tools/gn/config.h
@@ -9,11 +9,6 @@
 #include "tools/gn/config_values.h"
 #include "tools/gn/item.h"
 
-class Err;
-class ItemTree;
-class LocationRange;
-class Settings;
-
 // Represents a named config in the dependency graph.
 class Config : public Item {
  public:
@@ -26,16 +21,6 @@
   ConfigValues& config_values() { return config_values_; }
   const ConfigValues& config_values() const { return config_values_; }
 
-  // Gets or creates a config.
-  //
-  // This is like the TargetManager is for Targets, but Configs are so much
-  // simpler that this one function is all we need.
-  static Config* GetConfig(const Settings* settings,
-                           const LocationRange& specified_from_here,
-                           const Label& label,
-                           Item* dep_from,
-                           Err* err);
-
  private:
   ConfigValues config_values_;
 
diff --git a/tools/gn/config_values_generator.cc b/tools/gn/config_values_generator.cc
index 6f7fb22..f66ddfd 100644
--- a/tools/gn/config_values_generator.cc
+++ b/tools/gn/config_values_generator.cc
@@ -47,14 +47,13 @@
 
 }  // namespace
 
-ConfigValuesGenerator::ConfigValuesGenerator(ConfigValues* dest_values,
-                                             Scope* scope,
-                                             const Token& function_token,
-                                             const SourceDir& input_dir,
-                                             Err* err)
+ConfigValuesGenerator::ConfigValuesGenerator(
+    ConfigValues* dest_values,
+    Scope* scope,
+    const SourceDir& input_dir,
+    Err* err)
     : config_values_(dest_values),
       scope_(scope),
-      function_token_(function_token),
       input_dir_(input_dir),
       err_(err) {
 }
diff --git a/tools/gn/config_values_generator.h b/tools/gn/config_values_generator.h
index d58018e..eb8a2e6 100644
--- a/tools/gn/config_values_generator.h
+++ b/tools/gn/config_values_generator.h
@@ -16,11 +16,14 @@
 class Scope;
 class Token;
 
+// This class fills in the config values from a given scope. It's shared
+// between the "config" function call and all the different binary target types
+// (shared library, static library, etc.) since all of these support the
+// various flags stored in the ConfigValues class.
 class ConfigValuesGenerator {
  public:
   ConfigValuesGenerator(ConfigValues* dest_values,
                         Scope* scope,
-                        const Token& function_token,
                         const SourceDir& input_dir,
                         Err* err);
   ~ConfigValuesGenerator();
@@ -31,7 +34,6 @@
  private:
   ConfigValues* config_values_;
   Scope* scope_;
-  const Token& function_token_;
   const SourceDir input_dir_;
   Err* err_;
 
diff --git a/tools/gn/copy_target_generator.cc b/tools/gn/copy_target_generator.cc
index f02d4a7..b1b9076 100644
--- a/tools/gn/copy_target_generator.cc
+++ b/tools/gn/copy_target_generator.cc
@@ -6,14 +6,15 @@
 
 #include "tools/gn/build_settings.h"
 #include "tools/gn/filesystem_utils.h"
+#include "tools/gn/parse_tree.h"
 #include "tools/gn/scope.h"
 #include "tools/gn/value.h"
 
 CopyTargetGenerator::CopyTargetGenerator(Target* target,
                                          Scope* scope,
-                                         const Token& function_token,
+                                         const FunctionCallNode* function_call,
                                          Err* err)
-    : TargetGenerator(target, scope, function_token, err) {
+    : TargetGenerator(target, scope, function_call, err) {
 }
 
 CopyTargetGenerator::~CopyTargetGenerator() {
@@ -33,18 +34,16 @@
     return;
 
   if (target_->sources().empty()) {
-    *err_ = Err(function_token_, "Empty sources for copy command.",
+    *err_ = Err(function_call_, "Empty sources for copy command.",
         "You have to specify at least one file to copy in the \"sources\".");
     return;
   }
   if (target_->script_values().outputs().size() != 1) {
-    *err_ = Err(function_token_, "Copy command must have exactly one output.",
+    *err_ = Err(function_call_, "Copy command must have exactly one output.",
         "You must specify exactly one value in the \"outputs\" array for the "
         "destination of the copy\n(see \"gn help copy\"). If there are "
         "multiple sources to copy, use source expansion\n(see \"gn help "
         "source_expansion\").");
     return;
   }
-
-  SetToolchainDependency();
 }
diff --git a/tools/gn/copy_target_generator.h b/tools/gn/copy_target_generator.h
index b6f7e14..2361bff 100644
--- a/tools/gn/copy_target_generator.h
+++ b/tools/gn/copy_target_generator.h
@@ -13,7 +13,7 @@
  public:
   CopyTargetGenerator(Target* target,
                       Scope* scope,
-                      const Token& function_token,
+                      const FunctionCallNode* function_call,
                       Err* err);
   virtual ~CopyTargetGenerator();
 
diff --git a/tools/gn/function_set_default_toolchain.cc b/tools/gn/function_set_default_toolchain.cc
index c2b20a5..78f313f 100644
--- a/tools/gn/function_set_default_toolchain.cc
+++ b/tools/gn/function_set_default_toolchain.cc
@@ -4,10 +4,10 @@
 
 #include "tools/gn/build_settings.h"
 #include "tools/gn/functions.h"
+#include "tools/gn/loader.h"
 #include "tools/gn/parse_tree.h"
 #include "tools/gn/scope.h"
 #include "tools/gn/settings.h"
-#include "tools/gn/toolchain_manager.h"
 
 namespace functions {
 
@@ -52,8 +52,11 @@
     return Value();
   }
 
-  // Ignore non-default-build-config invocations.
-  if (!scope->IsProcessingDefaultBuildConfig())
+  // When the loader is expecting the default toolchain to be set, it will set
+  // this key on the scope to point to the destination.
+  Label* default_toolchain_dest = static_cast<Label*>(
+      scope->GetProperty(Loader::kDefaultToolchainKey, NULL));
+  if (!default_toolchain_dest)
     return Value();
 
   const SourceDir& current_dir = scope->GetSourceDir();
@@ -66,9 +69,7 @@
   if (toolchain_label.is_null())
     return Value();
 
-  ToolchainManager& mgr =
-      scope->settings()->build_settings()->toolchain_manager();
-  mgr.SetDefaultToolchainUnlocked(toolchain_label, function->GetRange(), err);
+  *default_toolchain_dest = toolchain_label;
   return Value();
 }
 
diff --git a/tools/gn/function_toolchain.cc b/tools/gn/function_toolchain.cc
index dde0306..cbd8826 100644
--- a/tools/gn/function_toolchain.cc
+++ b/tools/gn/function_toolchain.cc
@@ -98,14 +98,15 @@
   const SourceDir& input_dir = scope->GetSourceDir();
   Label label(input_dir, args[0].string_value());
   if (g_scheduler->verbose_logging())
-    g_scheduler->Log("Generating toolchain", label.GetUserVisibleName(false));
+    g_scheduler->Log("Definining toolchain", label.GetUserVisibleName(false));
 
   // This object will actually be copied into the one owned by the toolchain
   // manager, but that has to be done in the lock.
-  Toolchain toolchain(scope->settings(), label);
+  scoped_ptr<Toolchain> toolchain(new Toolchain(scope->settings(), label));
+  toolchain->set_defined_from(function);
 
   Scope block_scope(scope);
-  block_scope.SetProperty(&kToolchainPropertyKey, &toolchain);
+  block_scope.SetProperty(&kToolchainPropertyKey, toolchain.get());
   block->ExecuteBlockInScope(&block_scope, err);
   block_scope.SetProperty(&kToolchainPropertyKey, NULL);
   if (err->has_error())
@@ -113,17 +114,7 @@
   if (!block_scope.CheckForUnusedVars(err))
     return Value();
 
-  const BuildSettings* build_settings = scope->settings()->build_settings();
-  {
-    // Save the toolchain definition in the toolchain manager and mark the
-    // corresponding item in the dependency tree resolved so that targets
-    // that depend on this toolchain know it's ready.
-    base::AutoLock lock(build_settings->item_tree().lock());
-    build_settings->toolchain_manager().SetToolchainDefinitionLocked(
-        toolchain, function->GetRange(), err);
-    build_settings->item_tree().MarkItemDefinedLocked(build_settings, label,
-                                                      err);
-  }
+  scope->settings()->build_settings()->ItemDefined(toolchain.PassAs<Item>());
   return Value();
 }
 
diff --git a/tools/gn/functions.cc b/tools/gn/functions.cc
index 0e27297..96bc915 100644
--- a/tools/gn/functions.cc
+++ b/tools/gn/functions.cc
@@ -11,12 +11,10 @@
 #include "tools/gn/config_values_generator.h"
 #include "tools/gn/err.h"
 #include "tools/gn/input_file.h"
-#include "tools/gn/item_tree.h"
 #include "tools/gn/parse_tree.h"
 #include "tools/gn/scheduler.h"
 #include "tools/gn/scope.h"
 #include "tools/gn/settings.h"
-#include "tools/gn/target_manager.h"
 #include "tools/gn/token.h"
 #include "tools/gn/value.h"
 
@@ -261,29 +259,21 @@
   Label label(MakeLabelForScope(scope, function, args[0].string_value()));
 
   if (g_scheduler->verbose_logging())
-    g_scheduler->Log("Generating config", label.GetUserVisibleName(true));
+    g_scheduler->Log("Defining config", label.GetUserVisibleName(true));
 
-  // Create the empty config object.
-  ItemTree* tree = &scope->settings()->build_settings()->item_tree();
-  Config* config = Config::GetConfig(scope->settings(), function->GetRange(),
-                                     label, NULL, err);
-  if (err->has_error())
-    return Value();
+  // Create the new config.
+  scoped_ptr<Config> config(new Config(scope->settings(), label));
+  config->set_defined_from(function);
 
   // Fill it.
   const SourceDir& input_dir = scope->GetSourceDir();
-  ConfigValuesGenerator gen(&config->config_values(), scope,
-                            function->function(), input_dir, err);
+  ConfigValuesGenerator gen(&config->config_values(), scope, input_dir, err);
   gen.Run();
   if (err->has_error())
     return Value();
 
   // Mark as complete.
-  {
-    base::AutoLock lock(tree->lock());
-    tree->MarkItemDefinedLocked(scope->settings()->build_settings(), label,
-                                err);
-  }
+  scope->settings()->build_settings()->ItemDefined(config.PassAs<Item>());
   return Value();
 }
 
diff --git a/tools/gn/functions_target.cc b/tools/gn/functions_target.cc
index fc968e5..ceb0fbb 100644
--- a/tools/gn/functions_target.cc
+++ b/tools/gn/functions_target.cc
@@ -41,7 +41,7 @@
   if (err->has_error())
     return Value();
 
-  TargetGenerator::GenerateTarget(&block_scope, function->function(), args,
+  TargetGenerator::GenerateTarget(&block_scope, function, args,
                                   target_type, err);
   if (err->has_error())
     return Value();
@@ -109,7 +109,7 @@
   if (err->has_error())
     return Value();
 
-  TargetGenerator::GenerateTarget(&block_scope, function->function(), args,
+  TargetGenerator::GenerateTarget(&block_scope, function, args,
                                   component_mode, err);
   return Value();
 }
@@ -163,8 +163,7 @@
   if (!EnsureNotProcessingImport(function, scope, err) ||
       !EnsureNotProcessingBuildConfig(function, scope, err))
     return Value();
-  TargetGenerator::GenerateTarget(scope, function->function(), args,
-                                  functions::kCopy, err);
+  TargetGenerator::GenerateTarget(scope, function, args, functions::kCopy, err);
   return Value();
 }
 
diff --git a/tools/gn/gn.gyp b/tools/gn/gn.gyp
index a4f4c34..3a04387 100644
--- a/tools/gn/gn.gyp
+++ b/tools/gn/gn.gyp
@@ -16,6 +16,10 @@
         'binary_target_generator.h',
         'build_settings.cc',
         'build_settings.h',
+        'builder.cc',
+        'builder.h',
+        'builder_record.cc',
+        'builder_record.h',
         'command_args.cc',
         'command_desc.cc',
         'command_gen.cc',
@@ -72,13 +76,11 @@
         'input_file_manager.h',
         'item.cc',
         'item.h',
-        'item_node.cc',
-        'item_node.h',
-        'item_tree.cc',
-        'item_tree.h',
         'label.cc',
         'label.h',
         'label_ptr.h',
+        'loader.cc',
+        'loader.h',
         'location.cc',
         'location.h',
         'ninja_binary_target_writer.cc',
@@ -136,16 +138,12 @@
         'target.h',
         'target_generator.cc',
         'target_generator.h',
-        'target_manager.cc',
-        'target_manager.h',
         'token.cc',
         'token.h',
         'tokenizer.cc',
         'tokenizer.h',
         'toolchain.cc',
         'toolchain.h',
-        'toolchain_manager.cc',
-        'toolchain_manager.h',
         'trace.cc',
         'trace.h',
         'value.cc',
@@ -172,12 +170,14 @@
       'target_name': 'gn_unittests',
       'type': '<(gtest_target_type)',
       'sources': [
+        'builder_unittest.cc',
         'escape_unittest.cc',
         'file_template_unittest.cc',
         'filesystem_utils_unittest.cc',
         'function_rebase_path_unittest.cc',
         'input_conversion_unittest.cc',
         'label_unittest.cc',
+        'loader_unittest.cc',
         'ninja_binary_target_writer_unittest.cc',
         'ninja_helper_unittest.cc',
         'ninja_copy_target_writer_unittest.cc',
@@ -189,7 +189,6 @@
         'source_dir_unittest.cc',
         'string_utils_unittest.cc',
         'target_generator_unittest.cc',
-        'target_manager_unittest.cc',
         'target_unittest.cc',
         'test_with_scope.cc',
         'test_with_scope.h',
diff --git a/tools/gn/group_target_generator.cc b/tools/gn/group_target_generator.cc
index 30238e7..d52eb90 100644
--- a/tools/gn/group_target_generator.cc
+++ b/tools/gn/group_target_generator.cc
@@ -4,11 +4,12 @@
 
 #include "tools/gn/group_target_generator.h"
 
-GroupTargetGenerator::GroupTargetGenerator(Target* target,
-                                           Scope* scope,
-                                           const Token& function_token,
-                                           Err* err)
-    : TargetGenerator(target, scope, function_token, err) {
+GroupTargetGenerator::GroupTargetGenerator(
+    Target* target,
+    Scope* scope,
+    const FunctionCallNode* function_call,
+    Err* err)
+    : TargetGenerator(target, scope, function_call, err) {
 }
 
 GroupTargetGenerator::~GroupTargetGenerator() {
diff --git a/tools/gn/group_target_generator.h b/tools/gn/group_target_generator.h
index a88ec03..4739949 100644
--- a/tools/gn/group_target_generator.h
+++ b/tools/gn/group_target_generator.h
@@ -13,7 +13,7 @@
  public:
   GroupTargetGenerator(Target* target,
                         Scope* scope,
-                        const Token& function_token,
+                        const FunctionCallNode* function_call,
                         Err* err);
   virtual ~GroupTargetGenerator();
 
diff --git a/tools/gn/gyp_binary_target_writer.cc b/tools/gn/gyp_binary_target_writer.cc
index f668fd3..140ea15 100644
--- a/tools/gn/gyp_binary_target_writer.cc
+++ b/tools/gn/gyp_binary_target_writer.cc
@@ -7,6 +7,7 @@
 #include <set>
 
 #include "base/logging.h"
+#include "tools/gn/builder_record.h"
 #include "tools/gn/config_values_extractors.h"
 #include "tools/gn/err.h"
 #include "tools/gn/escape.h"
@@ -118,7 +119,7 @@
 
 GypBinaryTargetWriter::GypBinaryTargetWriter(const TargetGroup& group,
                                              std::ostream& out)
-    : GypTargetWriter(group.debug, out),
+    : GypTargetWriter(group.debug->item()->AsTarget(), out),
       group_(group) {
 }
 
@@ -193,12 +194,12 @@
   Indent(indent) << "'configurations': {\n";
 
   Indent(indent + kExtraIndent) << "'Debug': {\n";
-  Flags debug_flags(FlagsFromTarget(group_.debug));
+  Flags debug_flags(FlagsFromTarget(group_.debug->item()->AsTarget()));
   WriteVCFlags(debug_flags, indent + kExtraIndent * 2);
   Indent(indent + kExtraIndent) << "},\n";
 
   Indent(indent + kExtraIndent) << "'Release': {\n";
-  Flags release_flags(FlagsFromTarget(group_.release));
+  Flags release_flags(FlagsFromTarget(group_.release->item()->AsTarget()));
   WriteVCFlags(release_flags, indent + kExtraIndent * 2);
   Indent(indent + kExtraIndent) << "},\n";
 
@@ -221,15 +222,18 @@
     Indent(indent + kExtraIndent) << "['_toolset == \"host\"', {\n";
     Indent(indent + kExtraIndent * 2) << "'configurations': {\n";
     Indent(indent + kExtraIndent * 3) << "'Debug': {\n";
-    WriteLinuxFlagsForTarget(group_.host_debug, indent + kExtraIndent * 4);
+    WriteLinuxFlagsForTarget(group_.host_debug->item()->AsTarget(),
+                             indent + kExtraIndent * 4);
     Indent(indent + kExtraIndent * 3) << "},\n";
     Indent(indent + kExtraIndent * 3) << "'Release': {\n";
-    WriteLinuxFlagsForTarget(group_.host_release, indent + kExtraIndent * 4);
+    WriteLinuxFlagsForTarget(group_.host_release->item()->AsTarget(),
+                             indent + kExtraIndent * 4);
     Indent(indent + kExtraIndent * 3) << "},\n";
     Indent(indent + kExtraIndent * 2) << "}\n";
 
     // The sources are per-toolset but shared between debug & release.
-    WriteSources(group_.host_debug, indent + kExtraIndent * 2);
+    WriteSources(group_.host_debug->item()->AsTarget(),
+                 indent + kExtraIndent * 2);
 
     Indent(indent + kExtraIndent) << "],\n";
   }
@@ -238,10 +242,12 @@
   Indent(indent + kExtraIndent) << "['_toolset == \"target\"', {\n";
   Indent(indent + kExtraIndent * 2) << "'configurations': {\n";
   Indent(indent + kExtraIndent * 3) << "'Debug': {\n";
-  WriteLinuxFlagsForTarget(group_.debug, indent + kExtraIndent * 4);
+  WriteLinuxFlagsForTarget(group_.debug->item()->AsTarget(),
+                           indent + kExtraIndent * 4);
   Indent(indent + kExtraIndent * 3) << "},\n";
   Indent(indent + kExtraIndent * 3) << "'Release': {\n";
-  WriteLinuxFlagsForTarget(group_.release, indent + kExtraIndent * 4);
+  WriteLinuxFlagsForTarget(group_.release->item()->AsTarget(),
+                           indent + kExtraIndent * 4);
   Indent(indent + kExtraIndent * 3) << "},\n";
   Indent(indent + kExtraIndent * 2) << "},\n";
 
@@ -258,12 +264,12 @@
   Indent(indent) << "'configurations': {\n";
 
   Indent(indent + kExtraIndent) << "'Debug': {\n";
-  Flags debug_flags(FlagsFromTarget(group_.debug));
+  Flags debug_flags(FlagsFromTarget(group_.debug->item()->AsTarget()));
   WriteMacFlags(debug_flags, indent + kExtraIndent * 2);
   Indent(indent + kExtraIndent) << "},\n";
 
   Indent(indent + kExtraIndent) << "'Release': {\n";
-  Flags release_flags(FlagsFromTarget(group_.release));
+  Flags release_flags(FlagsFromTarget(group_.release->item()->AsTarget()));
   WriteMacFlags(release_flags, indent + kExtraIndent * 2);
   Indent(indent + kExtraIndent) << "},\n";
 
diff --git a/tools/gn/gyp_target_writer.cc b/tools/gn/gyp_target_writer.cc
index 8a55bdc..29cec2c 100644
--- a/tools/gn/gyp_target_writer.cc
+++ b/tools/gn/gyp_target_writer.cc
@@ -9,6 +9,7 @@
 #include "base/file_util.h"
 #include "base/files/file_path.h"
 #include "tools/gn/build_settings.h"
+#include "tools/gn/builder_record.h"
 #include "tools/gn/filesystem_utils.h"
 #include "tools/gn/gyp_binary_target_writer.h"
 #include "tools/gn/scheduler.h"
@@ -30,15 +31,16 @@
                                 Err* err) {
   if (targets.empty())
     return;
-  const BuildSettings* debug_build_settings =
-      targets[0].debug->settings()->build_settings();
+  const Settings* debug_settings =
+      targets[0].debug->item()->AsTarget()->settings();
+  const BuildSettings* debug_build_settings = debug_settings->build_settings();
 
   std::stringstream file;
   file << "# Generated by GN. Do not edit.\n\n";
   file << "{\n";
   file << "  'skip_includes': 1,\n";
 
-  if (targets[0].debug->settings()->IsMac()) {
+  if (debug_settings->IsMac()) {
     // Global settings for make/ninja. This must match common.gypi :(
     file << "  'make_global_settings': [\n";
     file << "    ['CC', 'third_party/llvm-build/Release+Asserts/bin/clang'],\n";
@@ -53,7 +55,8 @@
   file << "  'targets': [\n";
 
   for (size_t i = 0; i < targets.size(); i++) {
-    switch (targets[i].debug->output_type()) {
+    const Target* cur = targets[i].debug->item()->AsTarget();
+    switch (cur->output_type()) {
       case Target::COPY_FILES:
       case Target::CUSTOM:
       case Target::GROUP:
diff --git a/tools/gn/gyp_target_writer.h b/tools/gn/gyp_target_writer.h
index 27346b0..597a609 100644
--- a/tools/gn/gyp_target_writer.h
+++ b/tools/gn/gyp_target_writer.h
@@ -11,6 +11,7 @@
 #include "base/basictypes.h"
 #include "tools/gn/gyp_helper.h"
 
+class BuilderRecord;
 class Err;
 class Settings;
 class SourceFile;
@@ -25,10 +26,10 @@
           host_debug(NULL),
           host_release(NULL) {
     }
-    const Target* debug;
-    const Target* release;
-    const Target* host_debug;
-    const Target* host_release;
+    const BuilderRecord* debug;
+    const BuilderRecord* release;
+    const BuilderRecord* host_debug;
+    const BuilderRecord* host_release;
   };
 
   GypTargetWriter(const Target* target, std::ostream& out);
diff --git a/tools/gn/input_file_manager.cc b/tools/gn/input_file_manager.cc
index cc41039..0c4bf28 100644
--- a/tools/gn/input_file_manager.cc
+++ b/tools/gn/input_file_manager.cc
@@ -152,6 +152,9 @@
         base::AutoUnlock unlock(lock_);
         data->completion_event->Wait();
       }
+      // If there were multiple waiters on the same event, we now need to wake
+      // up the next one.
+      data->completion_event->Signal();
     }
   }
 
diff --git a/tools/gn/item.cc b/tools/gn/item.cc
index fa16975..f2fe9fe 100644
--- a/tools/gn/item.cc
+++ b/tools/gn/item.cc
@@ -8,7 +8,8 @@
 
 Item::Item(const Settings* settings, const Label& label)
     : settings_(settings),
-      label_(label) {
+      label_(label),
+      defined_from_(NULL) {
 }
 
 Item::~Item() {
diff --git a/tools/gn/item.h b/tools/gn/item.h
index 69115bd..4d9f25b 100644
--- a/tools/gn/item.h
+++ b/tools/gn/item.h
@@ -10,7 +10,7 @@
 #include "tools/gn/label.h"
 
 class Config;
-class ItemNode;
+class ParseNode;
 class Settings;
 class Target;
 class Toolchain;
@@ -28,12 +28,8 @@
   // accessed from any thread with no locking once the item is constructed.
   const Label& label() const { return label_; }
 
-  // The Item and the ItemNode make a pair. This will be set when the ItemNode
-  // is constructed that owns this Item. The ItemNode should only be
-  // dereferenced with the ItemTree lock held.
-  ItemNode* item_node() { return item_node_; }
-  const ItemNode* item_node() const { return item_node_; }
-  void set_item_node(ItemNode* in) { item_node_ = in; }
+  const ParseNode* defined_from() const { return defined_from_; }
+  void set_defined_from(const ParseNode* df) { defined_from_ = df; }
 
   // Manual RTTI.
   virtual Config* AsConfig();
@@ -54,8 +50,7 @@
  private:
   const Settings* settings_;
   Label label_;
-
-  ItemNode* item_node_;
+  const ParseNode* defined_from_;
 };
 
 #endif  // TOOLS_GN_ITEM_H_
diff --git a/tools/gn/item_node.cc b/tools/gn/item_node.cc
deleted file mode 100644
index 2143b06..0000000
--- a/tools/gn/item_node.cc
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "tools/gn/item_node.h"
-
-#include <algorithm>
-
-#include "base/callback.h"
-#include "base/logging.h"
-#include "tools/gn/build_settings.h"
-#include "tools/gn/item.h"
-
-ItemNode::ItemNode(Item* i)
-    : state_(REFERENCED),
-      item_(i),
-      should_generate_(false) {
-  item_->set_item_node(this);
-}
-
-ItemNode::~ItemNode() {
-}
-
-bool ItemNode::SetShouldGenerate(const BuildSettings* build_settings,
-                                 Err* err) {
-  if (should_generate_)
-    return true;
-  should_generate_ = true;
-
-  if (state_ == DEFINED) {
-    if (!ScheduleDepsLoad(build_settings, err))
-      return false;
-  } else if (state_ == RESOLVED) {
-    // The item may have been resolved even if we didn't set the generate bit
-    // if all of its deps were loaded some other way. In this case, we need
-    // to run the closure which we skipped when it became resolved.
-    if (!resolved_closure_.is_null())
-      resolved_closure_.Run();
-  }
-
-  // Pass the generate bit to all deps.
-  for (ItemNodeMap::iterator i = direct_dependencies_.begin();
-       i != direct_dependencies_.end(); ++i) {
-    if (!i->first->SetShouldGenerate(build_settings, err))
-      return false;
-  }
-  return true;
-}
-
-bool ItemNode::AddDependency(const BuildSettings* build_settings,
-                             const LocationRange& specified_from_here,
-                             ItemNode* node,
-                             Err* err) {
-  // Can't add more deps once it's been defined.
-  DCHECK(state_ == REFERENCED);
-
-  if (direct_dependencies_.find(node) != direct_dependencies_.end())
-    return true;  // Already have this dep.
-
-  direct_dependencies_[node] = specified_from_here;
-
-  if (node->state() != RESOLVED) {
-    // Wire up the pending resolution info.
-    unresolved_dependencies_[node] = specified_from_here;
-    node->waiting_on_resolution_[this] = specified_from_here;
-  }
-
-  if (should_generate_) {
-    if (!node->SetShouldGenerate(build_settings, err))
-      return false;
-  }
-  return true;
-}
-
-void ItemNode::MarkDirectDependencyResolved(ItemNode* node) {
-  DCHECK(unresolved_dependencies_.find(node) != unresolved_dependencies_.end());
-  unresolved_dependencies_.erase(node);
-}
-
-void ItemNode::SwapOutWaitingDependencySet(ItemNodeMap* out_map) {
-  waiting_on_resolution_.swap(*out_map);
-  DCHECK(waiting_on_resolution_.empty());
-}
-
-bool ItemNode::SetDefined(const BuildSettings* build_settings, Err* err) {
-  DCHECK(state_ == REFERENCED);
-  state_ = DEFINED;
-
-  if (should_generate_)
-    return ScheduleDepsLoad(build_settings, err);
-  return true;
-}
-
-void ItemNode::SetResolved() {
-  DCHECK(state_ != RESOLVED);
-  state_ = RESOLVED;
-
-  if (should_generate_ && !resolved_closure_.is_null())
-    resolved_closure_.Run();
-}
-
-bool ItemNode::ScheduleDepsLoad(const BuildSettings* build_settings,
-                                Err* err) {
-  DCHECK(state_ == DEFINED);
-  DCHECK(should_generate_);  // Shouldn't be requesting deps for ungenerated
-                             // items.
-
-  for (ItemNodeMap::const_iterator i = unresolved_dependencies_.begin();
-       i != unresolved_dependencies_.end(); ++i) {
-    Label toolchain_label = i->first->item()->label().GetToolchainLabel();
-    SourceDir dir_to_load = i->first->item()->label().dir();
-
-    if (!build_settings->toolchain_manager().ScheduleInvocationLocked(
-            i->second, toolchain_label, dir_to_load, err))
-      return false;
-  }
-
-  state_ = PENDING_DEPS;
-  return true;
-}
diff --git a/tools/gn/item_node.h b/tools/gn/item_node.h
deleted file mode 100644
index dbee141..0000000
--- a/tools/gn/item_node.h
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef TOOLS_GN_ITEM_NODE_H_
-#define TOOLS_GN_ITEM_NODE_H_
-
-#include <map>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/memory/scoped_ptr.h"
-#include "tools/gn/location.h"
-
-class BuildSettings;
-class Err;
-class Item;
-
-// Represents a node in the depdency tree. It references an Item which is
-// the actual thing.
-//
-// The items and nodes are split apart so that the ItemTree can manipulate
-// the dependencies one one thread while the Item itself is been modified on
-// another.
-class ItemNode {
- public:
-  // The state of this node. As more of the load progresses, we'll move
-  // downward in this list toward the resolved state.
-  enum State {
-    // Another item has referenced this one by name, but we have not yet
-    // encountered its definition.
-    REFERENCED = 0,
-
-    // We've seen the definition of this item but have not requested that its
-    // dependencies be loaded. In non-greedy generation mode (see item_tree.h)
-    // some nodes will stay in this state forever as long as they're not needed
-    // for anything that is required.
-    DEFINED,
-
-    // The item has been defined and we've requested that all of the
-    // dependencies be loaded. Not all of the dependencies have been resolved,
-    // however, and we're still waiting on some build files to be run (or
-    // perhaps there are undefined dependencies).
-    PENDING_DEPS,
-
-    // All of this item's transitive dependencies have been found and
-    // resolved.
-    RESOLVED,
-  };
-
-  // Stores a set of ItemNodes and the associated range that the dependency
-  // was added from.
-  typedef std::map<ItemNode*, LocationRange> ItemNodeMap;
-
-  // Takes ownership of the pointer.
-  // Initial state will be REFERENCED.
-  ItemNode(Item* i);
-  ~ItemNode();
-
-  State state() const { return state_; }
-
-  // This closure will be executed when the item is resolved and it has the
-  // should_generate flag set.
-  void set_resolved_closure(const base::Closure& closure) {
-    resolved_closure_ = closure;
-  }
-
-  const Item* item() const { return item_.get(); }
-  Item* item() { return item_.get(); }
-
-  // True if this item should be generated. In greedy mode, this will alwyas
-  // be set. Otherwise, this bit will be "pushed" through the tree to
-  // generate the minimum set of targets required for some special base target.
-  // Initialized to false.
-  //
-  // If this item has been defined, setting this flag will schedule the load
-  // of dependent nodes and also set their should_generate bits.
-  bool should_generate() const { return should_generate_; }
-  bool SetShouldGenerate(const BuildSettings* build_settings, Err* err);
-
-  // Where this was created from, which might be when it was generated or
-  // when it was first referenced from another target.
-  const LocationRange& originally_referenced_from_here() const {
-    return originally_referenced_from_here_;
-  }
-  void set_originally_referenced_from_here(const LocationRange& r) {
-    originally_referenced_from_here_ = r;
-  }
-
-  // Where this was generated from. This will be empty for items that have
-  // been referenced but not generated. Note that this has to be one the
-  // ItemNode because it can be changing from multiple threads and we need
-  // to be sure that access is serialized.
-  const LocationRange& generated_from_here() const {
-    return generated_from_here_;
-  }
-  void set_generated_from_here(const LocationRange& r) {
-    generated_from_here_ = r;
-  }
-
-  const ItemNodeMap& direct_dependencies() const {
-    return direct_dependencies_;
-  }
-  const ItemNodeMap& unresolved_dependencies() const {
-    return unresolved_dependencies_;
-  }
-
-  bool AddDependency(const BuildSettings* build_settings,
-                     const LocationRange& specified_from_here,
-                     ItemNode* node,
-                     Err* err);
-
-  // Removes the given dependency from the unresolved list. Does not do
-  // anything else to update waiters.
-  void MarkDirectDependencyResolved(ItemNode* node);
-
-  // Destructively retrieve the set of waiting nodes.
-  void SwapOutWaitingDependencySet(ItemNodeMap* out_map);
-
-  // Marks this item state as defined (see above). If the should generate
-  // flag is set, this will schedule a load of the dependencies and
-  // automatically transition to the PENDING_DEPS state.
-  bool SetDefined(const BuildSettings* build_settings, Err* err);
-
-  // Marks this item state as resolved (see above).
-  void SetResolved();
-
- private:
-  // Schedules loading the dependencies of this node. The current state must
-  // be DEFINED, and this call will transition the state to PENDING_DEPS.
-  //
-  // Requesting deps can fail. On failure returns false and sets the err.
-  bool ScheduleDepsLoad(const BuildSettings* build_settings, Err* err);
-
-  State state_;
-  scoped_ptr<Item> item_;
-  bool should_generate_;  // See getter above.
-
-  LocationRange originally_referenced_from_here_;
-  LocationRange generated_from_here_;
-
-  // What to run when this item is resolved.
-  base::Closure resolved_closure_;
-
-  // Everything this item directly depends on.
-  ItemNodeMap direct_dependencies_;
-
-  // Unresolved things this item directly depends on.
-  ItemNodeMap unresolved_dependencies_;
-
-  // These items are waiting on us to be resolved before they can be
-  // resolved. This is the backpointer for unresolved_dependencies_.
-  ItemNodeMap waiting_on_resolution_;
-
-  DISALLOW_COPY_AND_ASSIGN(ItemNode);
-};
-
-#endif  // TOOLS_GN_ITEM_NODE_H_
diff --git a/tools/gn/item_tree.cc b/tools/gn/item_tree.cc
deleted file mode 100644
index 42e005b..0000000
--- a/tools/gn/item_tree.cc
+++ /dev/null
@@ -1,208 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "tools/gn/item_tree.h"
-
-#include <algorithm>
-
-#include "base/stl_util.h"
-#include "tools/gn/err.h"
-#include "tools/gn/item.h"
-#include "tools/gn/item_node.h"
-
-namespace {
-
-// Recursively looks in the tree for a given node, returning true if it
-// was found in the dependecy graph. This is used to see if a given node
-// participates in a cycle.
-//
-// Note that "look_for" and "search_in" will be the same node when starting the
-// search, so we don't want to return true in that case.
-//
-// If a cycle is found, the return value will be true and the cycle vector will
-// be filled with the path (in reverse order).
-bool RecursiveFindCycle(const ItemNode* look_for,
-                        const ItemNode* search_in,
-                        std::vector<const ItemNode*>* cycle) {
-  const ItemNode::ItemNodeMap& unresolved =
-      search_in->unresolved_dependencies();
-  for (ItemNode::ItemNodeMap::const_iterator i = unresolved.begin();
-       i != unresolved.end(); ++i) {
-    ItemNode* cur = i->first;
-    if (cur == look_for) {
-      cycle->push_back(cur);
-      return true;
-    }
-
-    if (RecursiveFindCycle(look_for, cur, cycle)) {
-      // Found a cycle inside this one, record our path and return.
-      cycle->push_back(cur);
-      return true;
-    }
-  }
-  return false;
-}
-
-}  // namespace
-
-ItemTree::ItemTree() {
-}
-
-ItemTree::~ItemTree() {
-  STLDeleteContainerPairSecondPointers(items_.begin(), items_.end());
-}
-
-ItemNode* ItemTree::GetExistingNodeLocked(const Label& label) {
-  lock_.AssertAcquired();
-  StringToNodeHash::iterator found = items_.find(label);
-  if (found == items_.end())
-    return NULL;
-  return found->second;
-}
-
-void ItemTree::AddNodeLocked(ItemNode* node) {
-  lock_.AssertAcquired();
-  DCHECK(items_.find(node->item()->label()) == items_.end());
-  items_[node->item()->label()] = node;
-}
-
-bool ItemTree::MarkItemDefinedLocked(const BuildSettings* build_settings,
-                                     const Label& label,
-                                     Err* err) {
-  lock_.AssertAcquired();
-  DCHECK(items_.find(label) != items_.end());
-
-  ItemNode* node = items_[label];
-
-  if (!node->unresolved_dependencies().empty()) {
-    // Still some pending dependencies, wait for those to be resolved.
-    if (!node->SetDefined(build_settings, err))
-      return false;
-    return true;
-  }
-
-  // No more pending deps.
-  MarkItemResolvedLocked(node);
-  return true;
-}
-
-void ItemTree::GetAllItemNodesLocked(std::vector<const ItemNode*>* dest) const {
-  lock_.AssertAcquired();
-  dest->reserve(items_.size());
-  for (StringToNodeHash::const_iterator i = items_.begin();
-       i != items_.end(); ++i)
-    dest->push_back(i->second);
-}
-
-void ItemTree::GetAllItemsLocked(std::vector<const Item*>* dest) const {
-  lock_.AssertAcquired();
-  dest->reserve(items_.size());
-  for (StringToNodeHash::const_iterator i = items_.begin();
-       i != items_.end(); ++i) {
-    dest->push_back(i->second->item());
-  }
-}
-
-Err ItemTree::CheckForBadItems() const {
-  base::AutoLock lock(lock_);
-
-  // Look for errors where we find a GENERATED node that refers to a REFERENCED
-  // one. There may be other nodes depending on the GENERATED one, but listing
-  // all of those isn't helpful, we want to find the broken link.
-  //
-  // This finds normal "missing dependency" errors but does not find circular
-  // dependencies because in this case all items in the cycle will be GENERATED
-  // but none will be resolved. If this happens, we'll check explicitly for
-  // that below.
-  std::vector<const ItemNode*> bad_nodes;
-  std::string depstring;
-  for (StringToNodeHash::const_iterator i = items_.begin();
-       i != items_.end(); ++i) {
-    const ItemNode* src = i->second;
-    if (!src->should_generate())
-      continue;  // Skip ungenerated nodes.
-
-    if (src->state() == ItemNode::DEFINED ||
-        src->state() == ItemNode::PENDING_DEPS) {
-      bad_nodes.push_back(src);
-
-      // Check dependencies.
-      for (ItemNode::ItemNodeMap::const_iterator dest =
-               src->unresolved_dependencies().begin();
-          dest != src->unresolved_dependencies().end();
-          ++dest) {
-        const ItemNode* dest_node = dest->first;
-        if (dest_node->state() == ItemNode::REFERENCED) {
-          depstring += "\"" + src->item()->label().GetUserVisibleName(false) +
-              "\" needs " + dest_node->item()->GetItemTypeName() +
-              " \"" + dest_node->item()->label().GetUserVisibleName(false) +
-              "\"\n";
-        }
-      }
-    }
-  }
-
-  if (!bad_nodes.empty() && depstring.empty()) {
-    // Our logic above found a bad node but didn't identify the problem. This
-    // normally means a circular dependency.
-    depstring = CheckForCircularDependenciesLocked(bad_nodes);
-    if (depstring.empty()) {
-      // Something's very wrong, just dump out the bad nodes.
-      depstring = "I have no idea what went wrong, but these are unresolved, "
-          "possible due to an\ninternal error:";
-      for (size_t i = 0; i < bad_nodes.size(); i++) {
-        depstring += "\n\"" +
-            bad_nodes[i]->item()->label().GetUserVisibleName(false) + "\"";
-      }
-    }
-  }
-
-  if (depstring.empty())
-    return Err();
-  return Err(Location(), "Unresolved dependencies.", depstring);
-}
-
-void ItemTree::MarkItemResolvedLocked(ItemNode* node) {
-  node->SetResolved();
-  node->item()->OnResolved();
-
-  // Now update our waiters, pushing the "resolved" bit.
-  ItemNode::ItemNodeMap waiting;
-  node->SwapOutWaitingDependencySet(&waiting);
-  for (ItemNode::ItemNodeMap::iterator i = waiting.begin();
-       i != waiting.end(); ++i) {
-    ItemNode* waiter = i->first;
-
-    // Our node should be unresolved in the waiter.
-    DCHECK(waiter->unresolved_dependencies().find(node) !=
-           waiter->unresolved_dependencies().end());
-    waiter->MarkDirectDependencyResolved(node);
-
-    // Recursively mark nodes as resolved.
-    if ((waiter->state() == ItemNode::DEFINED ||
-         waiter->state() == ItemNode::PENDING_DEPS) &&
-        waiter->unresolved_dependencies().empty())
-      MarkItemResolvedLocked(waiter);
-  }
-}
-
-std::string ItemTree::CheckForCircularDependenciesLocked(
-    const std::vector<const ItemNode*>& bad_nodes) const {
-  std::vector<const ItemNode*> cycle;
-  if (!RecursiveFindCycle(bad_nodes[0], bad_nodes[0], &cycle))
-    return std::string();  // Didn't find a cycle, something else is wrong.
-
-  cycle.push_back(bad_nodes[0]);
-  std::string ret = "There is a dependency cycle:";
-
-  // Walk backwards since the dependency arrows point in the reverse direction.
-  for (int i = static_cast<int>(cycle.size()) - 1; i >= 0; i--) {
-    ret += "\n  \"" + cycle[i]->item()->label().GetUserVisibleName(false) +
-        "\"";
-    if (i != 0)
-      ret += " ->";
-  }
-
-  return ret;
-}
diff --git a/tools/gn/item_tree.h b/tools/gn/item_tree.h
deleted file mode 100644
index 59de49f..0000000
--- a/tools/gn/item_tree.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef TOOLS_GN_ITEM_TREE_H_
-#define TOOLS_GN_ITEM_TREE_H_
-
-#include "base/containers/hash_tables.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/synchronization/lock.h"
-#include "tools/gn/label.h"
-
-class BuildSettings;
-class Err;
-class Item;
-class ItemNode;
-
-// Represents the full dependency tree if labeled items in the system.
-// Generally you will interact with this through the target manager, etc.
-//
-// There are two modes for filling out the dependency tree:
-//
-// - In greedy mode, every target we encounter will be generated. This means
-//   that we'll recursively load all of its subdependencies. So if you have
-//   a build file that's loaded for any reason, all targets in that build file
-//   will be generated.
-//
-// - In non-greedy mode, we'll only generate and load dependncies for targets
-//   that have the should_generate bit set. This allows us to load the minimal
-//   set of buildfiles required for one or more targets.
-//
-// The main build is generally run in greedy mode, since people expect to be
-// be able to write random tests and have them show up in the output. We'll
-// switch into non-greed mode when doing diagnostics (like displaying the
-// dependency tree on the command line) and for dependencies on targets in
-// other toolchains. The toolchain behavior is important, if target A depends
-// on B with an alternate toolchain, it doesn't mean we should recursively
-// generate all targets in the buildfile just to get B: we should generate the
-// and load the minimum number of files in order to resolve B.
-class ItemTree {
- public:
-  ItemTree();
-  ~ItemTree();
-
-  // This lock must be held when calling the "Locked" functions below.
-  base::Lock& lock() const { return lock_; }
-
-  // Returns NULL if the item is not found.
-  //
-  // The lock must be held.
-  ItemNode* GetExistingNodeLocked(const Label& label);
-
-  // There must not be an item with this label in the tree already. Takes
-  // ownership of the pointer.
-  //
-  // The lock must be held.
-  void AddNodeLocked(ItemNode* node);
-
-  // Mark the given item as being defined. If it has no unresolved
-  // dependencies, it will be marked resolved, and the resolved state will be
-  // recursively pushed into the dependency tree. Returns an error if there was
-  // an error.
-  bool MarkItemDefinedLocked(const BuildSettings* build_settings,
-                             const Label& label,
-                             Err* err);
-
-  // Fills the given vector with all known items.
-  void GetAllItemNodesLocked(std::vector<const ItemNode*>* dest) const;
-  void GetAllItemsLocked(std::vector<const Item*>* dest) const;
-
-  // Returns an error if there are unresolved dependencies, or no error if
-  // there aren't.
-  //
-  // The lock should not be held.
-  Err CheckForBadItems() const;
-
- private:
-  void MarkItemResolvedLocked(ItemNode* node);
-
-  // Given a set of unresolved nodes, looks for cycles and returns the error
-  // message describing any cycles it found.
-  std::string CheckForCircularDependenciesLocked(
-      const std::vector<const ItemNode*>& bad_nodes) const;
-
-  mutable base::Lock lock_;
-
-  typedef base::hash_map<Label, ItemNode*> StringToNodeHash;
-  StringToNodeHash items_;  // Owning pointer.
-
-  DISALLOW_COPY_AND_ASSIGN(ItemTree);
-};
-
-#endif  // TOOLS_GN_ITEM_TREE_H_
diff --git a/tools/gn/label_ptr.h b/tools/gn/label_ptr.h
index 9bc3df2..9cff9d9 100644
--- a/tools/gn/label_ptr.h
+++ b/tools/gn/label_ptr.h
@@ -20,6 +20,9 @@
 
   LabelPtrPair() : label(), ptr(NULL), origin(NULL) {}
 
+  explicit LabelPtrPair(const Label& l) : label(l), ptr(NULL), origin(NULL) {
+  }
+
   // This contructor is typically used in unit tests, it extracts the label
   // automatically from a given pointer.
   explicit LabelPtrPair(const T* p) : label(p->label()), ptr(p), origin(NULL) {
diff --git a/tools/gn/loader.cc b/tools/gn/loader.cc
new file mode 100644
index 0000000..7e3ca3d
--- /dev/null
+++ b/tools/gn/loader.cc
@@ -0,0 +1,398 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "tools/gn/loader.h"
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "base/stl_util.h"
+#include "tools/gn/build_settings.h"
+#include "tools/gn/err.h"
+#include "tools/gn/filesystem_utils.h"
+#include "tools/gn/input_file_manager.h"
+#include "tools/gn/parse_tree.h"
+#include "tools/gn/scheduler.h"
+#include "tools/gn/scope_per_file_provider.h"
+#include "tools/gn/settings.h"
+#include "tools/gn/source_dir.h"
+#include "tools/gn/source_file.h"
+#include "tools/gn/trace.h"
+
+namespace {
+
+std::string GetOutputSubdirName(const Label& toolchain_label, bool is_default) {
+  // The default toolchain has no subdir.
+  if (is_default)
+    return std::string();
+
+  // For now just assume the toolchain name is always a valid dir name. We may
+  // want to clean up the in the future.
+  return toolchain_label.name();
+}
+
+}  // namespace
+
+// Identifies one time a file is loaded in a given toolchain so we don't load
+// it more than once.
+struct LoaderImpl::LoadID {
+  LoadID() {}
+  LoadID(const SourceFile& f, const Label& tc_name)
+      : file(f),
+        toolchain_name(tc_name) {
+  }
+
+  bool operator<(const LoadID& other) const {
+    if (file.value() == other.file.value())
+      return toolchain_name < other.toolchain_name;
+    return file < other.file;
+  }
+
+  SourceFile file;
+  Label toolchain_name;
+};
+
+// Our tracking information for a toolchain.
+struct LoaderImpl::ToolchainRecord {
+  // The default toolchain label can be empty for the first time the default
+  // toolchain is loaded, since we don't know it yet. This will be fixed up
+  // later. It should be valid in all other cases.
+  ToolchainRecord(const BuildSettings* build_settings,
+                  const Label& toolchain_label,
+                  const Label& default_toolchain_label)
+      : settings(build_settings,
+                 GetOutputSubdirName(toolchain_label,
+                     toolchain_label == default_toolchain_label)),
+        is_toolchain_loaded(false),
+        is_config_loaded(false) {
+    settings.set_default_toolchain_label(default_toolchain_label);
+    settings.set_toolchain_label(toolchain_label);
+  }
+
+  Settings settings;
+
+  bool is_toolchain_loaded;
+  bool is_config_loaded;
+
+  std::vector<SourceFile> waiting_on_me;
+};
+
+// -----------------------------------------------------------------------------
+
+const void* Loader::kDefaultToolchainKey = &kDefaultToolchainKey;
+
+Loader::Loader() {
+}
+
+Loader::~Loader() {
+}
+
+void Loader::Load(const Label& label) {
+  Load(BuildFileForLabel(label), label.GetToolchainLabel());
+}
+
+// static
+SourceFile Loader::BuildFileForLabel(const Label& label) {
+  return SourceFile(label.dir().value() + "BUILD.gn");
+}
+
+// -----------------------------------------------------------------------------
+
+LoaderImpl::LoaderImpl(const BuildSettings* build_settings)
+    : main_loop_(base::MessageLoop::current()),
+      pending_loads_(0),
+      build_settings_(build_settings) {
+}
+
+LoaderImpl::~LoaderImpl() {
+  STLDeleteContainerPairSecondPointers(toolchain_records_.begin(),
+                                       toolchain_records_.end());
+}
+
+void LoaderImpl::Load(const SourceFile& file,
+    const Label& in_toolchain_name) {
+  const Label& toolchain_name = in_toolchain_name.is_null()
+      ? default_toolchain_label_ : in_toolchain_name;
+  LoadID load_id(file, toolchain_name);
+  if (!invocations_.insert(load_id).second)
+    return;  // Already in set, so this file was already loaded or schedulerd.
+
+  if (toolchain_records_.empty()) {
+    // Nothing loaded, need to load the default build config. The intial load
+    // should not specify a toolchain.
+    DCHECK(toolchain_name.is_null());
+
+    ToolchainRecord* record =
+        new ToolchainRecord(build_settings_, Label(), Label());
+    toolchain_records_[Label()] = record;
+
+    // The default build config is no dependent on the toolchain definition,
+    // since we need to load the build config before we know what the default
+    // toolchain name is.
+    record->is_toolchain_loaded = true;
+
+    record->waiting_on_me.push_back(file);
+    ScheduleLoadBuildConfig(&record->settings, Scope::KeyValueMap());
+    return;
+  }
+
+  ToolchainRecord* record;
+  if (toolchain_name.is_null())
+    record = toolchain_records_[default_toolchain_label_];
+  else
+    record = toolchain_records_[toolchain_name];
+
+  if (!record) {
+    DCHECK(!default_toolchain_label_.is_null());
+
+    // No reference to this toolchain found yet, make one.
+    record = new ToolchainRecord(build_settings_, toolchain_name,
+                                 default_toolchain_label_);
+    toolchain_records_[toolchain_name] = record;
+
+    // Schedule a load of the toolchain using the default one.
+    Load(BuildFileForLabel(toolchain_name), default_toolchain_label_);
+  }
+
+  if (record->is_config_loaded)
+    ScheduleLoadFile(&record->settings, file);
+  else
+    record->waiting_on_me.push_back(file);
+}
+
+void LoaderImpl::ToolchainLoaded(const Toolchain* toolchain) {
+  ToolchainRecord* record = toolchain_records_[toolchain->label()];
+  if (!record) {
+    DCHECK(!default_toolchain_label_.is_null());
+    record = new ToolchainRecord(build_settings_, toolchain->label(),
+                                 default_toolchain_label_);
+    toolchain_records_[toolchain->label()] = record;
+  }
+  record->is_toolchain_loaded = true;
+
+  // The default build config is loaded first, then its toolchain. Secondary
+  // ones are loaded in the opposite order so we can pass toolchain parameters
+  // to the build config. So we may or may not have a config at this point.
+  if (!record->is_config_loaded) {
+    ScheduleLoadBuildConfig(&record->settings, toolchain->args());
+  } else {
+    // There should be nobody waiting on this if the build config is already
+    // loaded.
+    DCHECK(record->waiting_on_me.empty());
+  }
+}
+
+Label LoaderImpl::GetDefaultToolchain() const {
+  return default_toolchain_label_;
+}
+
+const Settings* LoaderImpl::GetToolchainSettings(const Label& label) {
+  ToolchainRecordMap::iterator found_toolchain;
+  if (label.is_null()) {
+    if (default_toolchain_label_.is_null())
+      return NULL;
+    found_toolchain = toolchain_records_.find(default_toolchain_label_);
+  } else {
+    found_toolchain = toolchain_records_.find(label);
+  }
+
+  if (found_toolchain == toolchain_records_.end())
+    return NULL;
+  return &found_toolchain->second->settings;
+}
+
+void LoaderImpl::ScheduleLoadFile(const Settings* settings,
+                                  const SourceFile& file) {
+  Err err;
+  pending_loads_++;
+  if (!AsyncLoadFile(LocationRange(), settings->build_settings(), file,
+                     base::Bind(&LoaderImpl::BackgroundLoadFile, this,
+                                settings, file),
+                     &err)) {
+    g_scheduler->FailWithError(err);
+    DecrementPendingLoads();
+  }
+}
+
+void LoaderImpl::ScheduleLoadBuildConfig(
+    Settings* settings,
+    const Scope::KeyValueMap& toolchain_overrides) {
+  Err err;
+  pending_loads_++;
+  if (!AsyncLoadFile(LocationRange(), settings->build_settings(),
+                     settings->build_settings()->build_config_file(),
+                     base::Bind(&LoaderImpl::BackgroundLoadBuildConfig,
+                                this, settings, toolchain_overrides),
+                     &err)) {
+    g_scheduler->FailWithError(err);
+    DecrementPendingLoads();
+  }
+}
+
+void LoaderImpl::BackgroundLoadFile(const Settings* settings,
+                                    const SourceFile& file_name,
+                                    const ParseNode* root) {
+  if (!root) {
+    main_loop_->PostTask(FROM_HERE,
+        base::Bind(&LoaderImpl::DecrementPendingLoads, this));
+    return;
+  }
+
+  if (g_scheduler->verbose_logging()) {
+    g_scheduler->Log("Running", file_name.value() + " with toolchain " +
+                     settings->toolchain_label().GetUserVisibleName(false));
+  }
+
+  Scope our_scope(settings->base_config());
+  ScopePerFileProvider per_file_provider(&our_scope);
+  our_scope.set_source_dir(file_name.GetDir());
+
+  ScopedTrace trace(TraceItem::TRACE_FILE_EXECUTE, file_name.value());
+  trace.SetToolchain(settings->toolchain_label());
+
+  Err err;
+  root->Execute(&our_scope, &err);
+  if (err.has_error())
+    g_scheduler->FailWithError(err);
+
+  trace.Done();
+
+  main_loop_->PostTask(FROM_HERE, base::Bind(&LoaderImpl::DidLoadFile, this));
+}
+
+void LoaderImpl::BackgroundLoadBuildConfig(
+    Settings* settings,
+    const Scope::KeyValueMap& toolchain_overrides,
+    const ParseNode* root) {
+  if (!root) {
+    main_loop_->PostTask(FROM_HERE,
+        base::Bind(&LoaderImpl::DecrementPendingLoads, this));
+    return;
+  }
+
+  Scope* base_config = settings->base_config();
+  base_config->set_source_dir(SourceDir("//"));
+
+  settings->build_settings()->build_args().SetupRootScope(
+      base_config, toolchain_overrides);
+
+  base_config->SetProcessingBuildConfig();
+
+  // See kDefaultToolchainKey in the header.
+  Label default_toolchain_label;
+  if (settings->is_default())
+    base_config->SetProperty(kDefaultToolchainKey, &default_toolchain_label);
+
+  ScopedTrace trace(TraceItem::TRACE_FILE_EXECUTE,
+      settings->build_settings()->build_config_file().value());
+  trace.SetToolchain(settings->toolchain_label());
+
+  const BlockNode* root_block = root->AsBlock();
+  Err err;
+  root_block->ExecuteBlockInScope(base_config, &err);
+
+  trace.Done();
+
+  base_config->ClearProcessingBuildConfig();
+  if (settings->is_default()) {
+    // The default toolchain must have been set in the default build config
+    // file.
+    if (default_toolchain_label.is_null()) {
+      g_scheduler->FailWithError(Err(Location(),
+          "The default build config file did not call set_default_toolchain()",
+          "If you don't call this, I can't figure out what toolchain to use\n"
+          "for all of this code."));
+    } else {
+      DCHECK(settings->toolchain_label().is_null());
+      settings->set_toolchain_label(default_toolchain_label);
+    }
+  }
+
+  main_loop_->PostTask(FROM_HERE,
+      base::Bind(&LoaderImpl::DidLoadBuildConfig, this,
+                 settings->toolchain_label()));
+}
+
+void LoaderImpl::DidLoadFile() {
+  DecrementPendingLoads();
+}
+
+void LoaderImpl::DidLoadBuildConfig(const Label& label) {
+  // Do not return early, we must call DecrementPendingLoads() at the bottom.
+
+  ToolchainRecordMap::iterator found_toolchain = toolchain_records_.find(label);
+  ToolchainRecord* record = NULL;
+  if (found_toolchain == toolchain_records_.end()) {
+    // When loading the default build config, we'll insert it into the record
+    // map with an empty label since we don't yet know what to call it.
+    //
+    // In this case, we should have exactly one entry in the map with an empty
+    // label. We now need to fix up the naming so it refers to the "real" one.
+    CHECK(toolchain_records_.size() == 1);
+    ToolchainRecordMap::iterator empty_label = toolchain_records_.find(Label());
+    CHECK(empty_label != toolchain_records_.end());
+
+    // Fix up the toolchain record.
+    record = empty_label->second;
+    toolchain_records_[label] = record;
+    toolchain_records_.erase(empty_label);
+
+    // Save the default toolchain label.
+    default_toolchain_label_ = label;
+    DCHECK(record->settings.default_toolchain_label().is_null());
+    record->settings.set_default_toolchain_label(label);
+
+    // The settings object should have the toolchain label already set.
+    DCHECK(!record->settings.toolchain_label().is_null());
+
+    // Update any stored invocations that refer to the empty toolchain label.
+    // This will normally only be one, for the root build file, so brute-force
+    // is OK.
+    LoadIDSet old_loads;
+    invocations_.swap(old_loads);
+    for (LoadIDSet::iterator i = old_loads.begin();
+         i != old_loads.end(); ++i) {
+      if (i->toolchain_name.is_null()) {
+        // Fix up toolchain label
+        invocations_.insert(LoadID(i->file, label));
+      } else {
+        // Can keep the old one.
+        invocations_.insert(*i);
+      }
+    }
+  } else {
+    record = found_toolchain->second;
+  }
+
+  DCHECK(!record->is_config_loaded);
+  DCHECK(record->is_toolchain_loaded);
+  record->is_config_loaded = true;
+
+  // Schedule all waiting file loads.
+  for (size_t i = 0; i < record->waiting_on_me.size(); i++)
+    ScheduleLoadFile(&record->settings, record->waiting_on_me[i]);
+  record->waiting_on_me.clear();
+
+  DecrementPendingLoads();
+}
+
+void LoaderImpl::DecrementPendingLoads() {
+  DCHECK(pending_loads_ > 0);
+  pending_loads_--;
+  if (pending_loads_ == 0 && !complete_callback_.is_null())
+    complete_callback_.Run();
+}
+
+bool LoaderImpl::AsyncLoadFile(
+    const LocationRange& origin,
+    const BuildSettings* build_settings,
+    const SourceFile& file_name,
+    const base::Callback<void(const ParseNode*)>& callback,
+    Err* err) {
+  if (async_load_file_.is_null()) {
+    return g_scheduler->input_file_manager()->AsyncLoadFile(
+        origin, build_settings, file_name, callback, err);
+  }
+  return async_load_file_.Run(
+      origin, build_settings, file_name, callback, err);
+}
diff --git a/tools/gn/loader.h b/tools/gn/loader.h
new file mode 100644
index 0000000..3b119c2
--- /dev/null
+++ b/tools/gn/loader.h
@@ -0,0 +1,177 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TOOLS_GN_LOADER_H_
+#define TOOLS_GN_LOADER_H_
+
+#include <map>
+#include <set>
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "tools/gn/label.h"
+#include "tools/gn/scope.h"
+
+namespace base {
+class MessageLoop;
+}
+
+class BuildSettings;
+class Settings;
+class SourceFile;
+class Toolchain;
+
+// The loader manages execution of the different build files. It receives
+// requests (normally from the Builder) when new references are found, and also
+// manages loading the build config files.
+//
+// This loader class is abstract so it can be mocked out for testing the
+// Builder.
+class Loader : public base::RefCountedThreadSafe<Loader> {
+ public:
+  Loader();
+
+  // Loads the given file in the conext of the given toolchain. The initial
+  // call to this (the one that actually starts the generation) should have an
+  // empty toolchain name, which will trigger the load of the default build
+  // config.
+  virtual void Load(const SourceFile& file,
+                    const Label& toolchain_name) = 0;
+
+  // Notification that the given toolchain has loaded. This will unblock files
+  // waiting on this definition.
+  virtual void ToolchainLoaded(const Toolchain* toolchain) = 0;
+
+  // Returns the label of the default toolchain.
+  virtual Label GetDefaultToolchain() const = 0;
+
+  // Returns information about the toolchain with the given label. Will return
+  // false if we haven't processed this toolchain yet.
+  virtual const Settings* GetToolchainSettings(const Label& label) = 0;
+
+  // Helper function that extracts the file and toolchain name from the given
+  // label, and calls Load().
+  void Load(const Label& label);
+
+  // Returns the build file that the given label references.
+  static SourceFile BuildFileForLabel(const Label& label);
+
+  // When processing the default build config, we want to capture the argument
+  // of set_default_build_config. The implementation of that function uses this
+  // constant as a property key to get the Label* out of the scope where the
+  // label should be stored.
+  static const void* kDefaultToolchainKey;
+
+ protected:
+  friend class base::RefCountedThreadSafe<Loader>;
+  virtual ~Loader();
+};
+
+class LoaderImpl : public Loader {
+ public:
+  // Callback to emulate InputFileManager::AsyncLoadFile.
+  typedef base::Callback<bool(const LocationRange&,
+                              const BuildSettings*,
+                              const SourceFile&,
+                              const base::Callback<void(const ParseNode*)>&,
+                              Err*)> AsyncLoadFileCallback;
+
+  LoaderImpl(const BuildSettings* build_settings);
+
+  // Loader implementation.
+  virtual void Load(const SourceFile& file,
+                    const Label& toolchain_name) OVERRIDE;
+  virtual void ToolchainLoaded(const Toolchain* toolchain) OVERRIDE;
+  virtual Label GetDefaultToolchain() const OVERRIDE;
+  virtual const Settings* GetToolchainSettings(const Label& label) OVERRIDE;
+
+  // Sets the message loop corresponding to the main thread. By default this
+  // class will use the thread active during construction, but there is not
+  // a message loop active during construction all the time.
+  void set_main_loop(base::MessageLoop* loop) { main_loop_ = loop; }
+
+  // The complete callback is called whenever there are no more pending loads.
+  // Called on the main thread only. This may be called more than once if the
+  // queue is drained, but then more stuff gets added.
+  void set_complete_callback(const base::Closure& cb) {
+    complete_callback_ = cb;
+  }
+
+  // This callback is used when the loader finds it wants to load a file.
+  void set_async_load_file(const AsyncLoadFileCallback& cb) {
+    async_load_file_ = cb;
+  }
+
+  const Label& default_toolchain_label() const {
+    return default_toolchain_label_;
+  }
+
+ private:
+  struct LoadID;
+  struct ToolchainRecord;
+
+  virtual ~LoaderImpl();
+
+  // Schedules the input file manager to load the given file.
+  void ScheduleLoadFile(const Settings* settings,
+                        const SourceFile& file);
+  void ScheduleLoadBuildConfig(
+      Settings* settings,
+      const Scope::KeyValueMap& toolchain_overrides);
+
+  // Runs the given file on the background thread. These are called by the
+  // input file manager.
+  void BackgroundLoadFile(const Settings* settings,
+                          const SourceFile& file_name,
+                          const ParseNode* root);
+  void BackgroundLoadBuildConfig(
+      Settings* settings,
+      const Scope::KeyValueMap& toolchain_overrides,
+      const ParseNode* root);
+
+  // Posted to the main thread when any file other than a build config file
+  // file has completed running.
+  void DidLoadFile();
+
+  // Posted to the main thread when any build config file has completed
+  // running. The label should be the name of the toolchain.
+  //
+  // If there is no defauled toolchain loaded yet, we'll assume that the first
+  // call to this indicates to the default toolchain, and this function will
+  // set the default toolchain name to the given label.
+  void DidLoadBuildConfig(const Label& label);
+
+  // Decrements the pending_loads_ variable and issues the complete callback if
+  // necessary.
+  void DecrementPendingLoads();
+
+  // Forwards to the appropriate location to load the file.
+  bool AsyncLoadFile(const LocationRange& origin,
+                     const BuildSettings* build_settings,
+                     const SourceFile& file_name,
+                     const base::Callback<void(const ParseNode*)>& callback,
+                     Err* err);
+
+  base::MessageLoop* main_loop_;
+
+  int pending_loads_;
+  base::Closure complete_callback_;
+
+  // When non-null, use this callback instead of the InputFileManager for
+  // mocking purposes.
+  AsyncLoadFileCallback async_load_file_;
+
+  typedef std::set<LoadID> LoadIDSet;
+  LoadIDSet invocations_;
+
+  const BuildSettings* build_settings_;
+  Label default_toolchain_label_;
+
+  // Records for the build config file loads.
+  // Owning pointers.
+  typedef std::map<Label, ToolchainRecord*> ToolchainRecordMap;
+  ToolchainRecordMap toolchain_records_;
+};
+
+#endif  // TOOLS_GN_LOADER_H_
diff --git a/tools/gn/loader_unittest.cc b/tools/gn/loader_unittest.cc
new file mode 100644
index 0000000..6397684
--- /dev/null
+++ b/tools/gn/loader_unittest.cc
@@ -0,0 +1,191 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/memory/linked_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "tools/gn/build_settings.h"
+#include "tools/gn/err.h"
+#include "tools/gn/loader.h"
+#include "tools/gn/parse_tree.h"
+#include "tools/gn/parser.h"
+#include "tools/gn/scheduler.h"
+#include "tools/gn/tokenizer.h"
+
+namespace {
+
+class MockInputFileManager {
+ public:
+  typedef base::Callback<void(const ParseNode*)> Callback;
+
+  MockInputFileManager() {
+  }
+
+  LoaderImpl::AsyncLoadFileCallback GetCallback();
+
+  // Sets a given response for a given source file.
+  void AddCannedResponse(const SourceFile& source_file,
+                         const std::string& source);
+
+  // Returns true if there is/are pending load(s) matching the given file(s).
+  bool HasOnePending(const SourceFile& f) const;
+  bool HasTwoPending(const SourceFile& f1, const SourceFile& f2) const;
+
+  void IssueAllPending();
+
+ private:
+  struct CannedResult {
+    scoped_ptr<InputFile> input_file;
+    std::vector<Token> tokens;
+    scoped_ptr<ParseNode> root;
+  };
+
+  bool AsyncLoadFile(const LocationRange& origin,
+                     const BuildSettings* build_settings,
+                     const SourceFile& file_name,
+                     const Callback& callback,
+                     Err* err) {
+    pending_.push_back(std::make_pair(file_name, callback));
+    return true;
+  }
+
+  // Owning pointers.
+  typedef std::map<SourceFile, linked_ptr<CannedResult> > CannedResponseMap;
+  CannedResponseMap canned_responses_;
+
+  std::vector< std::pair<SourceFile, Callback> > pending_;
+};
+
+LoaderImpl::AsyncLoadFileCallback MockInputFileManager::GetCallback() {
+  return base::Bind(&MockInputFileManager::AsyncLoadFile,
+                    base::Unretained(this));
+}
+
+// Sets a given response for a given source file.
+void MockInputFileManager::AddCannedResponse(const SourceFile& source_file,
+                                             const std::string& source) {
+  CannedResult* canned = new CannedResult;
+  canned->input_file.reset(new InputFile(source_file));
+  canned->input_file->SetContents(source);
+
+  // Tokenize.
+  Err err;
+  canned->tokens = Tokenizer::Tokenize(canned->input_file.get(), &err);
+  EXPECT_FALSE(err.has_error());
+
+  // Parse.
+  canned->root = Parser::Parse(canned->tokens, &err).Pass();
+  EXPECT_FALSE(err.has_error());
+
+  canned_responses_[source_file] = linked_ptr<CannedResult>(canned);
+}
+
+bool MockInputFileManager::HasOnePending(const SourceFile& f) const {
+  return pending_.size() == 1u && pending_[0].first == f;
+}
+
+bool MockInputFileManager::HasTwoPending(const SourceFile& f1,
+                                         const SourceFile& f2) const {
+  if (pending_.size() != 2u)
+    return false;
+  return pending_[0].first == f1 && pending_[1].first == f2;
+}
+
+void MockInputFileManager::IssueAllPending() {
+  BlockNode block(false);  // Default response.
+
+  for (size_t i = 0; i < pending_.size(); i++) {
+    CannedResponseMap::const_iterator found =
+        canned_responses_.find(pending_[i].first);
+    if (found == canned_responses_.end())
+      pending_[i].second.Run(&block);
+    else
+      pending_[i].second.Run(found->second->root.get());
+  }
+  pending_.clear();
+}
+
+// LoaderTest ------------------------------------------------------------------
+
+class LoaderTest : public testing::Test {
+ public:
+  LoaderTest() {
+    build_settings_.SetBuildDir(SourceDir("//out/Debug/"));
+  }
+  virtual ~LoaderTest() {
+  }
+
+ protected:
+  Scheduler scheduler_;
+  BuildSettings build_settings_;
+  MockInputFileManager mock_ifm_;
+};
+
+}  // namespace
+
+// -----------------------------------------------------------------------------
+
+TEST_F(LoaderTest, Foo) {
+  SourceFile build_config("//build/config/BUILDCONFIG.gn");
+  build_settings_.set_build_config_file(build_config);
+
+  scoped_refptr<LoaderImpl> loader(new LoaderImpl(&build_settings_));
+
+  // The default toolchain needs to be set by the build config file.
+  mock_ifm_.AddCannedResponse(build_config,
+                              "set_default_toolchain(\"//tc:tc\")");
+
+  loader->set_async_load_file(mock_ifm_.GetCallback());
+
+  // Request the root build file be loaded. This should kick off the default
+  // build config loading.
+  SourceFile root_build("//BUILD.gn");
+  loader->Load(root_build, Label());
+  EXPECT_TRUE(mock_ifm_.HasOnePending(build_config));
+
+  // Completing the build config load should kick off the root build file load.
+  mock_ifm_.IssueAllPending();
+  scheduler_.main_loop()->RunUntilIdle();
+  EXPECT_TRUE(mock_ifm_.HasOnePending(root_build));
+
+  // Load the root build file.
+  mock_ifm_.IssueAllPending();
+  scheduler_.main_loop()->RunUntilIdle();
+
+  // Schedule some other file to load in another toolchain.
+  Label second_tc(SourceDir("//tc2/"), "tc2");
+  SourceFile second_file("//foo/BUILD.gn");
+  loader->Load(second_file, second_tc);
+  EXPECT_TRUE(mock_ifm_.HasOnePending(SourceFile("//tc2/BUILD.gn")));
+
+  // Running the toolchain file should schedule the build config file to load
+  // for that toolchain.
+  mock_ifm_.IssueAllPending();
+  scheduler_.main_loop()->RunUntilIdle();
+
+  // We have to tell it we have a toolchain definition now (normally the
+  // builder would do this).
+  const Settings* default_settings = loader->GetToolchainSettings(Label());
+  Toolchain second_tc_object(default_settings, second_tc);
+  loader->ToolchainLoaded(&second_tc_object);
+  EXPECT_TRUE(mock_ifm_.HasOnePending(build_config));
+
+  // Scheduling a second file to load in that toolchain should not make it
+  // pending yet (it's waiting for the build config).
+  SourceFile third_file("//bar/BUILD.gn");
+  loader->Load(third_file, second_tc);
+  EXPECT_TRUE(mock_ifm_.HasOnePending(build_config));
+
+  // Running the build config file should make our third file pending.
+  mock_ifm_.IssueAllPending();
+  scheduler_.main_loop()->RunUntilIdle();
+  EXPECT_TRUE(mock_ifm_.HasTwoPending(second_file, third_file));
+
+  EXPECT_FALSE(scheduler_.is_failed());
+}
diff --git a/tools/gn/ninja_target_writer.cc b/tools/gn/ninja_target_writer.cc
index bdc0472..2b86626 100644
--- a/tools/gn/ninja_target_writer.cc
+++ b/tools/gn/ninja_target_writer.cc
@@ -35,14 +35,8 @@
 }
 
 // static
-void NinjaTargetWriter::RunAndWriteFile(const Target* target) {
-  // External targets don't get written to disk, we assume they're managed by
-  // an external program. If we're not using an external generator, this is
-  // ignored.
-  if (target->settings()->build_settings()->using_external_generator() &&
-      target->external())
-    return;
-
+void NinjaTargetWriter::RunAndWriteFile(const Target* target,
+                                        const Toolchain* toolchain) {
   const Settings* settings = target->settings();
   NinjaHelper helper(settings->build_settings());
 
@@ -57,10 +51,6 @@
   if (g_scheduler->verbose_logging())
     g_scheduler->Log("Writing", FilePathToUTF8(ninja_file));
 
-  const Toolchain* tc = settings->build_settings()->toolchain_manager()
-      .GetToolchainDefinitionUnlocked(settings->toolchain_label());
-  CHECK(tc);
-
   file_util::CreateDirectory(ninja_file.DirName());
 
   // It's rediculously faster to write to a string and then write that to
@@ -69,19 +59,19 @@
 
   // Call out to the correct sub-type of writer.
   if (target->output_type() == Target::COPY_FILES) {
-    NinjaCopyTargetWriter writer(target, tc, file);
+    NinjaCopyTargetWriter writer(target, toolchain, file);
     writer.Run();
   } else if (target->output_type() == Target::CUSTOM) {
-    NinjaScriptTargetWriter writer(target, tc, file);
+    NinjaScriptTargetWriter writer(target, toolchain, file);
     writer.Run();
   } else if (target->output_type() == Target::GROUP) {
-    NinjaGroupTargetWriter writer(target, tc, file);
+    NinjaGroupTargetWriter writer(target, toolchain, file);
     writer.Run();
   } else if (target->output_type() == Target::EXECUTABLE ||
              target->output_type() == Target::STATIC_LIBRARY ||
              target->output_type() == Target::SHARED_LIBRARY ||
              target->output_type() == Target::SOURCE_SET) {
-    NinjaBinaryTargetWriter writer(target, tc, file);
+    NinjaBinaryTargetWriter writer(target, toolchain, file);
     writer.Run();
   } else {
     CHECK(0);
diff --git a/tools/gn/ninja_target_writer.h b/tools/gn/ninja_target_writer.h
index e1c3bf8..937b240 100644
--- a/tools/gn/ninja_target_writer.h
+++ b/tools/gn/ninja_target_writer.h
@@ -24,7 +24,7 @@
                     std::ostream& out);
   virtual ~NinjaTargetWriter();
 
-  static void RunAndWriteFile(const Target* target);
+  static void RunAndWriteFile(const Target* target, const Toolchain* toolchain);
 
   virtual void Run() = 0;
 
diff --git a/tools/gn/ninja_toolchain_writer.cc b/tools/gn/ninja_toolchain_writer.cc
index 5f33e69..0a6b3de 100644
--- a/tools/gn/ninja_toolchain_writer.cc
+++ b/tools/gn/ninja_toolchain_writer.cc
@@ -9,21 +9,19 @@
 #include "base/file_util.h"
 #include "base/strings/stringize_macros.h"
 #include "tools/gn/build_settings.h"
-#include "tools/gn/item_node.h"
 #include "tools/gn/settings.h"
 #include "tools/gn/target.h"
 #include "tools/gn/toolchain.h"
-#include "tools/gn/toolchain_manager.h"
 #include "tools/gn/trace.h"
 
 NinjaToolchainWriter::NinjaToolchainWriter(
     const Settings* settings,
+    const Toolchain* toolchain,
     const std::vector<const Target*>& targets,
-    const std::set<std::string>& skip_files,
     std::ostream& out)
     : settings_(settings),
+      toolchain_(toolchain),
       targets_(targets),
-      skip_files_(skip_files),
       out_(out),
       path_output_(settings_->build_settings()->build_dir(),
                    ESCAPE_NINJA, true),
@@ -41,8 +39,8 @@
 // static
 bool NinjaToolchainWriter::RunAndWriteFile(
     const Settings* settings,
-    const std::vector<const Target*>& targets,
-    const std::set<std::string>& skip_files) {
+    const Toolchain* toolchain,
+    const std::vector<const Target*>& targets) {
   NinjaHelper helper(settings->build_settings());
   base::FilePath ninja_file(settings->build_settings()->GetFullPath(
       helper.GetNinjaFileForToolchain(settings).GetSourceFile(
@@ -57,16 +55,12 @@
   if (file.fail())
     return false;
 
-  NinjaToolchainWriter gen(settings, targets, skip_files, file);
+  NinjaToolchainWriter gen(settings, toolchain, targets, file);
   gen.Run();
   return true;
 }
 
 void NinjaToolchainWriter::WriteRules() {
-  const Toolchain* tc = settings_->build_settings()->toolchain_manager()
-      .GetToolchainDefinitionUnlocked(settings_->toolchain_label());
-  CHECK(tc);
-
   std::string indent("  ");
 
   NinjaHelper helper(settings_->build_settings());
@@ -74,7 +68,7 @@
 
   for (int i = Toolchain::TYPE_NONE + 1; i < Toolchain::TYPE_NUMTYPES; i++) {
     Toolchain::ToolType tool_type = static_cast<Toolchain::ToolType>(i);
-    const Toolchain::Tool& tool = tc->GetTool(tool_type);
+    const Toolchain::Tool& tool = toolchain_->GetTool(tool_type);
     if (tool.command.empty())
       continue;
 
@@ -100,15 +94,7 @@
 void NinjaToolchainWriter::WriteSubninjas() {
   // Write subninja commands for each generated target.
   for (size_t i = 0; i < targets_.size(); i++) {
-    if (!targets_[i]->item_node()->should_generate() ||
-        (targets_[i]->settings()->build_settings()->using_external_generator()
-         && targets_[i]->external()))
-      continue;
-
     OutputFile ninja_file = helper_.GetNinjaFileForTarget(targets_[i]);
-    if (skip_files_.find(ninja_file.value()) != skip_files_.end())
-      continue;
-
     out_ << "subninja ";
     path_output_.WriteFile(out_, ninja_file);
     out_ << std::endl;
diff --git a/tools/gn/ninja_toolchain_writer.h b/tools/gn/ninja_toolchain_writer.h
index 5d3daa5..ff0ebc0 100644
--- a/tools/gn/ninja_toolchain_writer.h
+++ b/tools/gn/ninja_toolchain_writer.h
@@ -16,20 +16,20 @@
 class BuildSettings;
 class Settings;
 class Target;
+class Toolchain;
 
 class NinjaToolchainWriter {
  public:
   // Takes the settings for the toolchain, as well as the list of all targets
-  // assicoated with the toolchain. Ninja files exactly matching "skip_files"
-  // will not be included in the subninja list.
+  // assicoated with the toolchain.
   static bool RunAndWriteFile(const Settings* settings,
-                              const std::vector<const Target*>& targets,
-                              const std::set<std::string>& skip_files);
+                              const Toolchain* toolchain,
+                              const std::vector<const Target*>& targets);
 
  private:
   NinjaToolchainWriter(const Settings* settings,
+                       const Toolchain* toolchain,
                        const std::vector<const Target*>& targets,
-                       const std::set<std::string>& skip_files,
                        std::ostream& out);
   ~NinjaToolchainWriter();
 
@@ -39,8 +39,8 @@
   void WriteSubninjas();
 
   const Settings* settings_;
+  const Toolchain* toolchain_;
   std::vector<const Target*> targets_;
-  const std::set<std::string>& skip_files_;
   std::ostream& out_;
   PathOutput path_output_;
 
diff --git a/tools/gn/ninja_writer.cc b/tools/gn/ninja_writer.cc
index 1fe893e..e4c0a22 100644
--- a/tools/gn/ninja_writer.cc
+++ b/tools/gn/ninja_writer.cc
@@ -4,25 +4,29 @@
 
 #include "tools/gn/ninja_writer.h"
 
+#include "tools/gn/builder.h"
+#include "tools/gn/loader.h"
 #include "tools/gn/location.h"
 #include "tools/gn/ninja_build_writer.h"
 #include "tools/gn/ninja_toolchain_writer.h"
 
-NinjaWriter::NinjaWriter(const BuildSettings* build_settings)
-    : build_settings_(build_settings) {
+NinjaWriter::NinjaWriter(const BuildSettings* build_settings,
+                         Builder* builder)
+    : build_settings_(build_settings),
+      builder_(builder) {
 }
 
 NinjaWriter::~NinjaWriter() {
 }
 
 // static
-bool NinjaWriter::RunAndWriteFiles(const BuildSettings* build_settings) {
-  NinjaWriter writer(build_settings);
+bool NinjaWriter::RunAndWriteFiles(const BuildSettings* build_settings,
+                                   Builder* builder) {
+  NinjaWriter writer(build_settings, builder);
 
   std::vector<const Settings*> all_settings;
   std::vector<const Target*> default_targets;
-  if (!writer.WriteToolchains(std::set<std::string>(),
-                              &all_settings, &default_targets))
+  if (!writer.WriteToolchains(&all_settings, &default_targets))
     return false;
   return writer.WriteRootBuildfiles(all_settings, default_targets);
 }
@@ -30,60 +34,54 @@
 // static
 bool NinjaWriter::RunAndWriteToolchainFiles(
     const BuildSettings* build_settings,
-    const std::set<std::string>& skip_files,
+    Builder* builder,
     std::vector<const Settings*>* all_settings) {
-  NinjaWriter writer(build_settings);
+  NinjaWriter writer(build_settings, builder);
   std::vector<const Target*> default_targets;
-  return writer.WriteToolchains(skip_files, all_settings, &default_targets);
+  return writer.WriteToolchains(all_settings, &default_targets);
 }
 
-bool NinjaWriter::WriteToolchains(
-    const std::set<std::string>& skip_files,
-    std::vector<const Settings*>* all_settings,
-    std::vector<const Target*>* default_targets) {
+bool NinjaWriter::WriteToolchains(std::vector<const Settings*>* all_settings,
+                                  std::vector<const Target*>* default_targets) {
   // Categorize all targets by toolchain.
   typedef std::map<Label, std::vector<const Target*> > CategorizedMap;
   CategorizedMap categorized;
 
-  std::vector<const Target*> all_targets;
-  build_settings_->target_manager().GetAllTargets(&all_targets);
-  if (all_targets.empty()) {
+  std::vector<const BuilderRecord*> all_records = builder_->GetAllRecords();
+  for (size_t i = 0; i < all_records.size(); i++) {
+    if (all_records[i]->type() == BuilderRecord::ITEM_TARGET &&
+        all_records[i]->should_generate()) {
+      categorized[all_records[i]->label().GetToolchainLabel()].push_back(
+          all_records[i]->item()->AsTarget());
+      }
+  }
+  if (categorized.empty()) {
     Err(Location(), "No targets.",
         "I could not find any targets to write, so I'm doing nothing.")
         .PrintToStdout();
     return false;
   }
-  for (size_t i = 0; i < all_targets.size(); i++) {
-    categorized[all_targets[i]->label().GetToolchainLabel()].push_back(
-        all_targets[i]);
-  }
 
-  Label default_label =
-      build_settings_->toolchain_manager().GetDefaultToolchainUnlocked();
+  Label default_label = builder_->loader()->GetDefaultToolchain();
 
   // Write out the toolchain buildfiles, and also accumulate the set of
   // all settings and find the list of targets in the default toolchain.
   for (CategorizedMap::const_iterator i = categorized.begin();
        i != categorized.end(); ++i) {
-    const Settings* settings;
-    {
-      base::AutoLock lock(build_settings_->item_tree().lock());
-      Err ignored;
-      settings =
-          build_settings_->toolchain_manager().GetSettingsForToolchainLocked(
-              LocationRange(), i->first, &ignored);
-    }
+    const Settings* settings =
+        builder_->loader()->GetToolchainSettings(i->first);
+    const Toolchain* toolchain = builder_->GetToolchain(i->first);
+
     all_settings->push_back(settings);
-    if (!NinjaToolchainWriter::RunAndWriteFile(settings, i->second,
-                                               skip_files)) {
+    if (!NinjaToolchainWriter::RunAndWriteFile(settings, toolchain,
+                                               i->second)) {
       Err(Location(),
           "Couldn't open toolchain buildfile(s) for writing").PrintToStdout();
       return false;
     }
   }
 
-  *default_targets = categorized[
-      build_settings_->toolchain_manager().GetDefaultToolchainUnlocked()];
+  *default_targets = categorized[default_label];
   return true;
 }
 
diff --git a/tools/gn/ninja_writer.h b/tools/gn/ninja_writer.h
index c2efc92..8859f1a 100644
--- a/tools/gn/ninja_writer.h
+++ b/tools/gn/ninja_writer.h
@@ -11,6 +11,7 @@
 
 #include "base/basictypes.h"
 
+class Builder;
 class BuildSettings;
 class Settings;
 class Target;
@@ -18,31 +19,28 @@
 class NinjaWriter {
  public:
   // On failure will print an error and will return false.
-  static bool RunAndWriteFiles(const BuildSettings* build_settings);
+  static bool RunAndWriteFiles(const BuildSettings* build_settings,
+                               Builder* builder);
 
   // Writes only the toolchain.ninja files, skipping the root buildfile. The
   // settings for the files written will be added to the vector.
-  //
-  // The skip files will avoid writing "subninja" rules when we're doing a
-  // side-by-side GYP build. .ninja files exactly matching the ones in the set
-  // will be ignored.
   static bool RunAndWriteToolchainFiles(
       const BuildSettings* build_settings,
-      const std::set<std::string>& skip_files,
+      Builder* builder,
       std::vector<const Settings*>* all_settings);
 
  private:
-  NinjaWriter(const BuildSettings* build_settings);
+  NinjaWriter(const BuildSettings* build_settings, Builder* builder);
   ~NinjaWriter();
 
   bool WriteToolchains(
-      const std::set<std::string>& skip_files,
       std::vector<const Settings*>* all_settings,
       std::vector<const Target*>* default_targets);
   bool WriteRootBuildfiles(const std::vector<const Settings*>& all_settings,
                            const std::vector<const Target*>& default_targets);
 
   const BuildSettings* build_settings_;
+  Builder* builder_;
 
   DISALLOW_COPY_AND_ASSIGN(NinjaWriter);
 };
diff --git a/tools/gn/scheduler.cc b/tools/gn/scheduler.cc
index 72c310b..254de0d 100644
--- a/tools/gn/scheduler.cc
+++ b/tools/gn/scheduler.cc
@@ -7,7 +7,6 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/strings/string_number_conversions.h"
-#include "tools/gn/ninja_target_writer.h"
 #include "tools/gn/standard_out.h"
 
 Scheduler* g_scheduler = NULL;
@@ -31,17 +30,22 @@
       input_file_manager_(new InputFileManager),
       verbose_logging_(false),
       work_count_(0),
-      is_failed_(false) {
+      is_failed_(false),
+      has_been_shutdown_(false) {
   g_scheduler = this;
 }
 
 Scheduler::~Scheduler() {
+  if (!has_been_shutdown_)
+    pool_->Shutdown();
   g_scheduler = NULL;
 }
 
 bool Scheduler::Run() {
   runner_.Run();
+  base::AutoLock lock(lock_);
   pool_->Shutdown();
+  has_been_shutdown_ = true;
   return !is_failed();
 }
 
@@ -86,13 +90,6 @@
       base::SequencedWorkerPool::BLOCK_SHUTDOWN);
 }
 
-void Scheduler::ScheduleTargetFileWrite(const Target* target) {
-  pool_->PostWorkerTaskWithShutdownBehavior(
-      FROM_HERE, base::Bind(&Scheduler::DoTargetFileWrite,
-                            base::Unretained(this), target),
-      base::SequencedWorkerPool::BLOCK_SHUTDOWN);
-}
-
 void Scheduler::AddGenDependency(const base::FilePath& file) {
   base::AutoLock lock(lock_);
   gen_dependencies_.push_back(file);
@@ -130,10 +127,6 @@
   runner_.Quit();
 }
 
-void Scheduler::DoTargetFileWrite(const Target* target) {
-  NinjaTargetWriter::RunAndWriteFile(target);
-}
-
 void Scheduler::DoWork(const base::Closure& closure) {
   closure.Run();
   DecrementWorkCount();
diff --git a/tools/gn/scheduler.h b/tools/gn/scheduler.h
index 4b2c060..8f4a133 100644
--- a/tools/gn/scheduler.h
+++ b/tools/gn/scheduler.h
@@ -40,7 +40,7 @@
 
   void ScheduleWork(const base::Closure& work);
 
-  void ScheduleTargetFileWrite(const Target* target);
+  void Shutdown();
 
   // Declares that the given file was read and affected the build output.
   //
@@ -79,6 +79,11 @@
   mutable base::Lock lock_;
   bool is_failed_;
 
+  // Used to track whether the worker pool has been shutdown. This is necessary
+  // to clean up after tests that make a scheduler but don't run the message
+  // loop.
+  bool has_been_shutdown_;
+
   // Additional input dependencies. Protected by the lock.
   std::vector<base::FilePath> gen_dependencies_;
 
diff --git a/tools/gn/scope.cc b/tools/gn/scope.cc
index 42277f7..052c55d 100644
--- a/tools/gn/scope.cc
+++ b/tools/gn/scope.cc
@@ -13,8 +13,7 @@
 // FLags set in the mode_flags_ of a scope. If a bit is set, it applies
 // recursively to all dependent scopes.
 const unsigned kProcessingBuildConfigFlag = 1;
-const unsigned kProcessingDefaultBuildConfigFlag = 2;
-const unsigned kProcessingImportFlag = 4;
+const unsigned kProcessingImportFlag = 2;
 
 }  // namespace
 
@@ -303,24 +302,6 @@
   return false;
 }
 
-void Scope::SetProcessingDefaultBuildConfig() {
-  DCHECK((mode_flags_ & kProcessingDefaultBuildConfigFlag) == 0);
-  mode_flags_ |= kProcessingDefaultBuildConfigFlag;
-}
-
-void Scope::ClearProcessingDefaultBuildConfig() {
-  DCHECK(mode_flags_ & kProcessingDefaultBuildConfigFlag);
-  mode_flags_ &= ~(kProcessingDefaultBuildConfigFlag);
-}
-
-bool Scope::IsProcessingDefaultBuildConfig() const {
-  if (mode_flags_ & kProcessingDefaultBuildConfigFlag)
-    return true;
-  if (containing())
-    return containing()->IsProcessingDefaultBuildConfig();
-  return false;
-}
-
 void Scope::SetProcessingImport() {
   DCHECK((mode_flags_ & kProcessingImportFlag) == 0);
   mode_flags_ |= kProcessingImportFlag;
diff --git a/tools/gn/scope.h b/tools/gn/scope.h
index 0d1c156..d4a35ff 100644
--- a/tools/gn/scope.h
+++ b/tools/gn/scope.h
@@ -165,8 +165,7 @@
   }
 
   // Indicates if we're currently processing the build configuration file.
-  // This is true when processing the config file for any toolchain. See also
-  // *ProcessingDefaultBuildConfig() below.
+  // This is true when processing the config file for any toolchain.
   //
   // To set or clear the flag, it must currently be in the opposite state in
   // the current scope. Note that querying the state of the flag recursively
@@ -176,12 +175,6 @@
   void ClearProcessingBuildConfig();
   bool IsProcessingBuildConfig() const;
 
-  // Indicates we're currently processing the default toolchain's build
-  // configuration file.
-  void SetProcessingDefaultBuildConfig();
-  void ClearProcessingDefaultBuildConfig();
-  bool IsProcessingDefaultBuildConfig() const;
-
   // Indicates if we're currently processing an import file.
   //
   // See SetProcessingBaseConfig for how flags work.
diff --git a/tools/gn/scope_per_file_provider.cc b/tools/gn/scope_per_file_provider.cc
index 1f4bc25..c2fdd3e 100644
--- a/tools/gn/scope_per_file_provider.cc
+++ b/tools/gn/scope_per_file_provider.cc
@@ -7,7 +7,6 @@
 #include "tools/gn/filesystem_utils.h"
 #include "tools/gn/settings.h"
 #include "tools/gn/source_file.h"
-#include "tools/gn/toolchain_manager.h"
 #include "tools/gn/value.h"
 #include "tools/gn/variables.h"
 
@@ -50,10 +49,8 @@
 
 const Value* ScopePerFileProvider::GetDefaultToolchain() {
   if (!default_toolchain_) {
-    const ToolchainManager& toolchain_manager =
-        scope_->settings()->build_settings()->toolchain_manager();
     default_toolchain_.reset(new Value(NULL,
-        toolchain_manager.GetDefaultToolchainUnlocked().GetUserVisibleName(
+        scope_->settings()->default_toolchain_label().GetUserVisibleName(
             false)));
   }
   return default_toolchain_.get();
diff --git a/tools/gn/script_target_generator.cc b/tools/gn/script_target_generator.cc
index 272061c..8f414f4 100644
--- a/tools/gn/script_target_generator.cc
+++ b/tools/gn/script_target_generator.cc
@@ -7,16 +7,18 @@
 #include "tools/gn/build_settings.h"
 #include "tools/gn/err.h"
 #include "tools/gn/filesystem_utils.h"
+#include "tools/gn/parse_tree.h"
 #include "tools/gn/scope.h"
 #include "tools/gn/value.h"
 #include "tools/gn/value_extractors.h"
 #include "tools/gn/variables.h"
 
-ScriptTargetGenerator::ScriptTargetGenerator(Target* target,
-                                             Scope* scope,
-                                             const Token& function_token,
-                                             Err* err)
-    : TargetGenerator(target, scope, function_token, err) {
+ScriptTargetGenerator::ScriptTargetGenerator(
+    Target* target,
+    Scope* scope,
+    const FunctionCallNode* function_call,
+    Err* err)
+    : TargetGenerator(target, scope, function_call, err) {
 }
 
 ScriptTargetGenerator::~ScriptTargetGenerator() {
@@ -62,7 +64,7 @@
   // if it doesn't have one.
   const Value* value = scope_->GetValue(variables::kScript, true);
   if (!value) {
-    *err_ = Err(function_token_, "This target type requires a \"script\".");
+    *err_ = Err(function_call_, "This target type requires a \"script\".");
     return;
   }
   if (!value->VerifyTypeIs(Value::STRING, err_))
diff --git a/tools/gn/script_target_generator.h b/tools/gn/script_target_generator.h
index f693145..4d79e51 100644
--- a/tools/gn/script_target_generator.h
+++ b/tools/gn/script_target_generator.h
@@ -13,7 +13,7 @@
  public:
   ScriptTargetGenerator(Target* target,
                         Scope* scope,
-                        const Token& function_token,
+                        const FunctionCallNode* function_call,
                         Err* err);
   virtual ~ScriptTargetGenerator();
 
@@ -29,4 +29,3 @@
 };
 
 #endif  // TOOLS_GN_SCRIPT_TARGET_GENERATOR_H_
-
diff --git a/tools/gn/secondary/base/BUILD.gn b/tools/gn/secondary/base/BUILD.gn
index 0f104a3..d6dc507 100644
--- a/tools/gn/secondary/base/BUILD.gn
+++ b/tools/gn/secondary/base/BUILD.gn
@@ -260,7 +260,6 @@
     "mac/sdk_forward_declarations.h",
     "memory/aligned_memory.cc",
     "memory/aligned_memory.h",
-    "memory/discardable_memory.cc",
     "memory/discardable_memory.h",
     "memory/discardable_memory_android.cc",
     "memory/discardable_memory_mac.cc",
@@ -880,8 +879,6 @@
     "test/expectations/parser.h",
     "test/gtest_xml_util.cc",
     "test/gtest_xml_util.h",
-    "test/launcher/parallel_test_launcher.cc",
-    "test/launcher/parallel_test_launcher.h",
     "test/launcher/test_launcher.cc",
     "test/launcher/test_launcher.h",
     "test/launcher/test_result.cc",
diff --git a/tools/gn/settings.cc b/tools/gn/settings.cc
index b8de976..2715829 100644
--- a/tools/gn/settings.cc
+++ b/tools/gn/settings.cc
@@ -11,7 +11,6 @@
 Settings::Settings(const BuildSettings* build_settings,
                    const std::string& output_subdir_name)
     : build_settings_(build_settings),
-      is_default_(false),
       import_manager_(),
       base_config_(this),
       greedy_target_generation_(false) {
@@ -23,6 +22,7 @@
     toolchain_output_subdir_.value().append(output_subdir_name);
     toolchain_output_subdir_.value().push_back('/');
 
+    DCHECK(!build_settings->build_dir().is_null());
     toolchain_output_dir_ = SourceDir(build_settings->build_dir().value() +
                                       toolchain_output_subdir_.value());
   }
@@ -44,5 +44,3 @@
 
 Settings::~Settings() {
 }
-
-
diff --git a/tools/gn/settings.h b/tools/gn/settings.h
index df6a3d6..f2e8925 100644
--- a/tools/gn/settings.h
+++ b/tools/gn/settings.h
@@ -46,9 +46,17 @@
   const Label& toolchain_label() const { return toolchain_label_; }
   void set_toolchain_label(const Label& l) { toolchain_label_ = l; }
 
+  const Label& default_toolchain_label() const {
+    return default_toolchain_label_;
+  }
+  void set_default_toolchain_label(const Label& default_label) {
+    default_toolchain_label_ = default_label;
+  }
+
   // Indicates if this corresponds to the default toolchain.
-  bool is_default() const { return is_default_; }
-  void set_is_default(bool id) { is_default_ = id; }
+  bool is_default() const {
+    return toolchain_label_ == default_toolchain_label_;
+  }
 
   bool IsMac() const { return target_os_ == MAC; }
   bool IsLinux() const { return target_os_ == LINUX; }
@@ -94,7 +102,7 @@
   const BuildSettings* build_settings_;
 
   Label toolchain_label_;
-  bool is_default_;
+  Label default_toolchain_label_;
 
   TargetOS target_os_;
 
diff --git a/tools/gn/setup.cc b/tools/gn/setup.cc
index ae02bf1..4f18f57 100644
--- a/tools/gn/setup.cc
+++ b/tools/gn/setup.cc
@@ -6,6 +6,7 @@
 
 #include <stdlib.h>
 
+#include "base/bind.h"
 #include "base/command_line.h"
 #include "base/file_util.h"
 #include "base/files/file_path.h"
@@ -141,17 +142,37 @@
 }
 #endif
 
+// Called on any thread. Post the item to the builder on the main thread.
+void ItemDefinedCallback(base::MessageLoop* main_loop,
+                         scoped_refptr<Builder> builder,
+                         scoped_ptr<Item> item) {
+  DCHECK(item);
+  main_loop->PostTask(FROM_HERE, base::Bind(&Builder::ItemDefined, builder,
+                                            base::Passed(&item)));
+}
+
+void DecrementWorkCount() {
+  g_scheduler->DecrementWorkCount();
+}
+
 }  // namespace
 
 // CommonSetup -----------------------------------------------------------------
 
 CommonSetup::CommonSetup()
-    : check_for_bad_items_(true) {
+    : build_settings_(),
+      loader_(new LoaderImpl(&build_settings_)),
+      builder_(new Builder(loader_.get())),
+      check_for_bad_items_(true) {
+  loader_->set_complete_callback(base::Bind(&DecrementWorkCount));
 }
 
 CommonSetup::CommonSetup(const CommonSetup& other)
     : build_settings_(other.build_settings_),
+      loader_(new LoaderImpl(&build_settings_)),
+      builder_(new Builder(loader_.get())),
       check_for_bad_items_(other.check_for_bad_items_) {
+  loader_->set_complete_callback(base::Bind(&DecrementWorkCount));
 }
 
 CommonSetup::~CommonSetup() {
@@ -159,15 +180,16 @@
 
 void CommonSetup::RunPreMessageLoop() {
   // Load the root build file.
-  build_settings_.toolchain_manager().StartLoadingUnlocked(
-      SourceFile("//BUILD.gn"));
+  loader_->Load(SourceFile("//BUILD.gn"), Label());
+
+  // Will be decremented with the loader is drained.
+  g_scheduler->IncrementWorkCount();
 }
 
 bool CommonSetup::RunPostMessageLoop() {
   Err err;
   if (check_for_bad_items_) {
-    err = build_settings_.item_tree().CheckForBadItems();
-    if (err.has_error()) {
+    if (!builder_->CheckForBadItems(&err)) {
       err.PrintToStdout();
       return false;
     }
@@ -195,6 +217,12 @@
       empty_settings_(&empty_build_settings_, std::string()),
       dotfile_scope_(&empty_settings_) {
   empty_settings_.set_toolchain_label(Label());
+  build_settings_.set_item_defined_callback(
+      base::Bind(&ItemDefinedCallback, scheduler_.main_loop(), builder_));
+
+  // The scheduler's main loop wasn't created when the Loader was created, so
+  // we need to set it now.
+  loader_->set_main_loop(scheduler_.main_loop());
 }
 
 Setup::~Setup() {
@@ -411,8 +439,11 @@
 
 // DependentSetup --------------------------------------------------------------
 
-DependentSetup::DependentSetup(const Setup& main_setup)
+DependentSetup::DependentSetup(Setup& main_setup)
     : CommonSetup(main_setup) {
+  build_settings_.set_item_defined_callback(
+      base::Bind(&ItemDefinedCallback, main_setup.scheduler().main_loop(),
+                 builder_));
 }
 
 DependentSetup::~DependentSetup() {
diff --git a/tools/gn/setup.h b/tools/gn/setup.h
index 8b6d714..a5f9e76 100644
--- a/tools/gn/setup.h
+++ b/tools/gn/setup.h
@@ -11,6 +11,8 @@
 #include "base/files/file_path.h"
 #include "base/memory/scoped_ptr.h"
 #include "tools/gn/build_settings.h"
+#include "tools/gn/builder.h"
+#include "tools/gn/loader.h"
 #include "tools/gn/scheduler.h"
 #include "tools/gn/scope.h"
 #include "tools/gn/settings.h"
@@ -33,6 +35,8 @@
   void set_check_for_bad_items(bool s) { check_for_bad_items_ = s; }
 
   BuildSettings& build_settings() { return build_settings_; }
+  Builder* builder() { return builder_.get(); }
+  LoaderImpl* loader() { return loader_.get(); }
 
  protected:
   CommonSetup();
@@ -43,8 +47,9 @@
   void RunPreMessageLoop();
   bool RunPostMessageLoop();
 
- protected:
   BuildSettings build_settings_;
+  scoped_refptr<LoaderImpl> loader_;
+  scoped_refptr<Builder> builder_;
 
   bool check_for_bad_items_;
 
@@ -121,7 +126,7 @@
 // so that the main setup executes the message loop, but both are run.
 class DependentSetup : public CommonSetup {
  public:
-  DependentSetup(const Setup& main_setup);
+  DependentSetup(Setup& main_setup);
   virtual ~DependentSetup();
 
   // These are the two parts of Run() in the regular setup, not including the
diff --git a/tools/gn/target.cc b/tools/gn/target.cc
index 28dcf91..b12d284 100644
--- a/tools/gn/target.cc
+++ b/tools/gn/target.cc
@@ -60,9 +60,7 @@
     : Item(settings, label),
       output_type_(UNKNOWN),
       hard_dep_(false),
-      external_(false),
-      generated_(false),
-      generator_function_(NULL) {
+      external_(false) {
 }
 
 Target::~Target() {
@@ -152,23 +150,6 @@
     // pulled from G to A in case G has configs directly on it).
     PullDependentTargetInfo(&unique_configs);
   }
-
-  // Mark as resolved.
-  if (!settings()->build_settings()->target_resolved_callback().is_null()) {
-    g_scheduler->ScheduleWork(base::Bind(&TargetResolvedThunk,
-        settings()->build_settings()->target_resolved_callback(),
-        this));
-  }
-}
-
-bool Target::HasBeenGenerated() const {
-  return generated_;
-}
-
-void Target::SetGenerated(const Token* token) {
-  DCHECK(!generated_);
-  generated_ = true;
-  generator_function_ = token;
 }
 
 bool Target::IsLinkable() const {
@@ -190,11 +171,8 @@
       inherited_libraries_.insert(dep);
 
     // Inherited libraries and flags are inherited across static library
-    // boundaries. For external targets, assume that the external_link_deps
-    // will take care of this.
-    if ((!dep->external() ||
-         !settings()->build_settings()->using_external_generator()) &&
-        dep->output_type() != SHARED_LIBRARY &&
+    // boundaries.
+    if (dep->output_type() != SHARED_LIBRARY &&
         dep->output_type() != EXECUTABLE) {
       const std::set<const Target*> inherited = dep->inherited_libraries();
       for (std::set<const Target*>::const_iterator i = inherited.begin();
diff --git a/tools/gn/target.h b/tools/gn/target.h
index 13b278c..58f0de1 100644
--- a/tools/gn/target.h
+++ b/tools/gn/target.h
@@ -51,13 +51,6 @@
   virtual const Target* AsTarget() const OVERRIDE;
   virtual void OnResolved() OVERRIDE;
 
-  // This flag indicates if we've run the TargetGenerator for this target to
-  // fill out the rest of the values. Once we've done this, we save the
-  // location of the function that started the generating so that we can detect
-  // duplicate declarations.
-  bool HasBeenGenerated() const;
-  void SetGenerated(const Token* token);
-
   OutputType output_type() const { return output_type_; }
   void set_output_type(OutputType t) { output_type_ = t; }
 
@@ -192,9 +185,6 @@
 
   SourceFile gyp_file_;
 
-  bool generated_;
-  const Token* generator_function_;  // Who generated this: for error messages.
-
   DISALLOW_COPY_AND_ASSIGN(Target);
 };
 
diff --git a/tools/gn/target_generator.cc b/tools/gn/target_generator.cc
index 3bb51eb..81c4394 100644
--- a/tools/gn/target_generator.cc
+++ b/tools/gn/target_generator.cc
@@ -12,12 +12,10 @@
 #include "tools/gn/filesystem_utils.h"
 #include "tools/gn/functions.h"
 #include "tools/gn/group_target_generator.h"
-#include "tools/gn/item_node.h"
 #include "tools/gn/parse_tree.h"
 #include "tools/gn/scheduler.h"
 #include "tools/gn/scope.h"
 #include "tools/gn/script_target_generator.h"
-#include "tools/gn/target_manager.h"
 #include "tools/gn/token.h"
 #include "tools/gn/value.h"
 #include "tools/gn/value_extractors.h"
@@ -25,11 +23,11 @@
 
 TargetGenerator::TargetGenerator(Target* target,
                                  Scope* scope,
-                                 const Token& function_token,
+                                 const FunctionCallNode* function_call,
                                  Err* err)
     : target_(target),
       scope_(scope),
-      function_token_(function_token),
+      function_call_(function_call),
       err_(err) {
 }
 
@@ -43,26 +41,19 @@
   FillDependencies();
   FillGypFile();
 
-  // To type-specific generation.
+  // Do type-specific generation.
   DoRun();
-
-  // Mark the target as complete.
-  if (!err_->has_error()) {
-    target_->SetGenerated(&function_token_);
-    GetBuildSettings()->target_manager().TargetGenerationComplete(
-        target_->label(), err_);
-  }
 }
 
 // static
 void TargetGenerator::GenerateTarget(Scope* scope,
-                                     const Token& function_token,
+                                     const FunctionCallNode* function_call,
                                      const std::vector<Value>& args,
                                      const std::string& output_type,
                                      Err* err) {
   // Name is the argument to the function.
   if (args.size() != 1u || args[0].type() != Value::STRING) {
-    *err = Err(function_token,
+    *err = Err(function_call,
         "Target generator requires one string argument.",
         "Otherwise I'm not sure what to call this target.");
     return;
@@ -75,44 +66,44 @@
               toolchain_label.dir(), toolchain_label.name());
 
   if (g_scheduler->verbose_logging())
-    g_scheduler->Log("Generating target", label.GetUserVisibleName(true));
+    g_scheduler->Log("Defining target", label.GetUserVisibleName(true));
 
-  Target* target =
-      scope->settings()->build_settings()->target_manager().GetTarget(
-          label, function_token.range(), NULL, err);
-  if (err->has_error())
-    return;
+  scoped_ptr<Target> target(new Target(scope->settings(), label));
+  target->set_defined_from(function_call);
 
   // Create and call out to the proper generator.
   if (output_type == functions::kCopy) {
-    CopyTargetGenerator generator(target, scope, function_token, err);
+    CopyTargetGenerator generator(target.get(), scope, function_call, err);
     generator.Run();
   } else if (output_type == functions::kCustom) {
-    ScriptTargetGenerator generator(target, scope, function_token, err);
+    ScriptTargetGenerator generator(target.get(), scope, function_call, err);
     generator.Run();
   } else if (output_type == functions::kExecutable) {
-    BinaryTargetGenerator generator(target, scope, function_token,
+    BinaryTargetGenerator generator(target.get(), scope, function_call,
                                     Target::EXECUTABLE, err);
     generator.Run();
   } else if (output_type == functions::kGroup) {
-    GroupTargetGenerator generator(target, scope, function_token, err);
+    GroupTargetGenerator generator(target.get(), scope, function_call, err);
     generator.Run();
   } else if (output_type == functions::kSharedLibrary) {
-    BinaryTargetGenerator generator(target, scope, function_token,
+    BinaryTargetGenerator generator(target.get(), scope, function_call,
                                     Target::SHARED_LIBRARY, err);
     generator.Run();
   } else if (output_type == functions::kSourceSet) {
-    BinaryTargetGenerator generator(target, scope, function_token,
+    BinaryTargetGenerator generator(target.get(), scope, function_call,
                                     Target::SOURCE_SET, err);
     generator.Run();
   } else if (output_type == functions::kStaticLibrary) {
-    BinaryTargetGenerator generator(target, scope, function_token,
+    BinaryTargetGenerator generator(target.get(), scope, function_call,
                                     Target::STATIC_LIBRARY, err);
     generator.Run();
   } else {
-    *err = Err(function_token, "Not a known output type",
+    *err = Err(function_call, "Not a known output type",
                "I am very confused.");
   }
+
+  if (!err->has_error())
+    scope->settings()->build_settings()->ItemDefined(target.PassAs<Item>());
 }
 
 const BuildSettings* TargetGenerator::GetBuildSettings() const {
@@ -155,8 +146,6 @@
 }
 
 void TargetGenerator::FillData() {
-  // TODO(brettW) hook this up to the constant when we have cleaned up
-  // how data files are used.
   const Value* value = scope_->GetValue(variables::kData, true);
   if (!value)
     return;
@@ -229,88 +218,30 @@
   target_->script_values().outputs().swap(outputs);
 }
 
-void TargetGenerator::SetToolchainDependency() {
-  // TODO(brettw) currently we lock separately for each config, dep, and
-  // toolchain we add which is bad! Do this in one lock.
-  ItemTree* tree = &GetBuildSettings()->item_tree();
-  base::AutoLock lock(tree->lock());
-  ItemNode* tc_node =
-      tree->GetExistingNodeLocked(ToolchainLabelForScope(scope_));
-  target_->item_node()->AddDependency(
-      GetBuildSettings(), function_token_.range(), tc_node, err_);
-}
-
 void TargetGenerator::FillGenericConfigs(const char* var_name,
                                          LabelConfigVector* dest) {
   const Value* value = scope_->GetValue(var_name, true);
-  if (!value)
-    return;
-  if (!ExtractListOfLabels(*value, scope_->GetSourceDir(),
-                           ToolchainLabelForScope(scope_), dest, err_))
-    return;
-
-  for (size_t i = 0; i < dest->size(); i++) {
-    LabelConfigPair& cur = (*dest)[i];
-    cur.ptr = Config::GetConfig(scope_->settings(),
-                                value->list_value()[i].origin()->GetRange(),
-                                cur.label, target_, err_);
-    if (err_->has_error())
-      return;
+  if (value) {
+    ExtractListOfLabels(*value, scope_->GetSourceDir(),
+                        ToolchainLabelForScope(scope_), dest, err_);
   }
 }
 
 void TargetGenerator::FillGenericDeps(const char* var_name,
                                       LabelTargetVector* dest) {
   const Value* value = scope_->GetValue(var_name, true);
-  if (!value)
-    return;
-  if (!ExtractListOfLabels(*value, scope_->GetSourceDir(),
-                           ToolchainLabelForScope(scope_), dest, err_))
-    return;
-
-  for (size_t i = 0; i < dest->size(); i++) {
-    LabelTargetPair& cur = (*dest)[i];
-    cur.ptr = GetBuildSettings()->target_manager().GetTarget(
-        cur.label, value->list_value()[i].origin()->GetRange(), target_, err_);
-    if (err_->has_error())
-      return;
+  if (value) {
+    ExtractListOfLabels(*value, scope_->GetSourceDir(),
+                        ToolchainLabelForScope(scope_), dest, err_);
   }
 }
 
 void TargetGenerator::FillForwardDependentConfigs() {
   const Value* value = scope_->GetValue(
       variables::kForwardDependentConfigsFrom, true);
-  if (!value)
-    return;
-
-  LabelTargetVector& dest = target_->forward_dependent_configs();
-  if (!ExtractListOfLabels(*value, scope_->GetSourceDir(),
-                           ToolchainLabelForScope(scope_), &dest, err_))
-    return;
-
-  // We currently assume that the list is very small and do a brute-force
-  // search in the deps for the labeled target. This could be optimized.
-  const LabelTargetVector& deps = target_->deps();
-  std::vector<const Target*> forward_from_list;
-  for (size_t dest_index = 0; dest_index < dest.size(); dest_index++) {
-    LabelTargetPair& cur_dest = dest[dest_index];
-    for (size_t dep_index = 0; dep_index < deps.size(); dep_index++) {
-      if (deps[dep_index].label == cur_dest.label) {
-        cur_dest.ptr = deps[dep_index].ptr;
-        break;
-      }
-    }
-    if (!cur_dest.ptr) {
-      *err_ = Err(cur_dest.origin,
-          "Can't forward from this target.",
-          "forward_dependent_configs_from must contain a list of labels that\n"
-          "must all appear in the deps of the same target.");
-      return;
-    }
+  if (value) {
+    ExtractListOfLabels(*value, scope_->GetSourceDir(),
+                        ToolchainLabelForScope(scope_),
+                        &target_->forward_dependent_configs(), err_);
   }
 }
-
-
-
-
-
diff --git a/tools/gn/target_generator.h b/tools/gn/target_generator.h
index 583e57f..6fa39b1 100644
--- a/tools/gn/target_generator.h
+++ b/tools/gn/target_generator.h
@@ -15,9 +15,9 @@
 
 class BuildSettings;
 class Err;
+class FunctionCallNode;
 class Location;
 class Scope;
-class Token;
 class Value;
 
 // Fills the variables in a Target object from a Scope (the result of a script
@@ -28,16 +28,16 @@
  public:
   TargetGenerator(Target* target,
                   Scope* scope,
-                  const Token& function_token,
+                  const FunctionCallNode* function_call,
                   Err* err);
   ~TargetGenerator();
 
   void Run();
 
-  // The function token is the token of the function name of the generator for
-  // this target. err() will be set on failure.
+  // The function call is the parse tree node that invoked the target.
+  // err() will be set on failure.
   static void GenerateTarget(Scope* scope,
-                             const Token& function_token,
+                             const FunctionCallNode* function_call,
                              const std::vector<Value>& args,
                              const std::string& output_type,
                              Err* err);
@@ -54,13 +54,9 @@
   void FillExternal();
   void FillOutputs();
 
-  // Sets the current toolchain as a dependecy of this target. All targets with
-  // a dependency on the toolchain should call this function.
-  void SetToolchainDependency();
-
   Target* target_;
   Scope* scope_;
-  const Token& function_token_;
+  const FunctionCallNode* function_call_;
   Err* err_;
 
  private:
diff --git a/tools/gn/target_manager.cc b/tools/gn/target_manager.cc
deleted file mode 100644
index eb5c86d..0000000
--- a/tools/gn/target_manager.cc
+++ /dev/null
@@ -1,129 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "tools/gn/target_manager.h"
-
-#include <deque>
-
-#include "base/bind.h"
-#include "base/strings/string_piece.h"
-#include "tools/gn/build_settings.h"
-#include "tools/gn/err.h"
-#include "tools/gn/filesystem_utils.h"
-#include "tools/gn/item_node.h"
-#include "tools/gn/scheduler.h"
-#include "tools/gn/toolchain_manager.h"
-#include "tools/gn/value.h"
-
-TargetManager::TargetManager(const BuildSettings* build_settings)
-    : build_settings_(build_settings) {
-}
-
-TargetManager::~TargetManager() {
-}
-
-Target* TargetManager::GetTarget(const Label& label,
-                                 const LocationRange& specified_from_here,
-                                 Target* dep_from,
-                                 Err* err) {
-  DCHECK(!label.is_null());
-  DCHECK(!label.toolchain_dir().value().empty());
-  DCHECK(!label.toolchain_name().empty());
-
-  base::AutoLock lock(build_settings_->item_tree().lock());
-
-  ItemNode* target_node =
-      build_settings_->item_tree().GetExistingNodeLocked(label);
-  Target* target = NULL;
-  if (!target_node) {
-    // First time we've seen this, may need to load the file.
-
-    // Compute the settings. The common case is that we have a dep_from and
-    // the toolchains match, so we can use the settings from there rather than
-    // querying the toolchain manager (which requires locking, etc.).
-    const Settings* settings;
-    if (dep_from && dep_from->label().ToolchainsEqual(label)) {
-      settings = dep_from->settings();
-    } else {
-      settings =
-          build_settings_->toolchain_manager().GetSettingsForToolchainLocked(
-              specified_from_here, label.GetToolchainLabel(), err);
-      if (!settings)
-        return NULL;
-    }
-
-    target = new Target(settings, label);
-
-    target_node = new ItemNode(target);
-    if (settings->greedy_target_generation()) {
-      if (!target_node->SetShouldGenerate(build_settings_, err))
-        return NULL;
-    }
-    target_node->set_originally_referenced_from_here(specified_from_here);
-
-    build_settings_->item_tree().AddNodeLocked(target_node);
-
-    // We're generating a node when there is no referencing one.
-    if (!dep_from)
-      target_node->set_generated_from_here(specified_from_here);
-
-  } else if ((target = target_node->item()->AsTarget())) {
-    // Previously saw this item as a target.
-
-    // If we have no dep_from, we're generating it.
-    if (!dep_from) {
-      // In this case, it had better not already be generated.
-      if (target_node->state() != ItemNode::REFERENCED) {
-        *err = Err(specified_from_here,
-                   "Duplicate target.",
-                   "\"" + label.GetUserVisibleName(true) +
-                   "\" being defined here.");
-        err->AppendSubErr(Err(target_node->generated_from_here(),
-                              "Originally defined here."));
-        return NULL;
-      } else {
-        target_node->set_generated_from_here(specified_from_here);
-      }
-    }
-  } else {
-    // Error, we previously saw this thing as a non-target.
-    *err = Err(specified_from_here, "Not previously a target.",
-        "The target being declared here was previously seen referenced as a " +
-        target_node->item()->GetItemTypeName());
-    err->AppendSubErr(Err(target_node->originally_referenced_from_here(),
-                          "Originally referenced from here."));
-    return NULL;
-  }
-
-  // Keep a record of the guy asking us for this dependency. We know if
-  // somebody is adding a dependency, that guy it himself not resolved.
-  if (dep_from && target_node->state() != ItemNode::RESOLVED) {
-    ItemNode* from_node = dep_from->item_node();
-    if (!from_node->AddDependency(build_settings_, specified_from_here,
-                                  target_node, err))
-      return NULL;
-  }
-
-  return target;
-}
-
-bool TargetManager::TargetGenerationComplete(const Label& label,
-                                             Err* err) {
-  base::AutoLock lock(build_settings_->item_tree().lock());
-  return build_settings_->item_tree().MarkItemDefinedLocked(
-      build_settings_, label, err);
-}
-
-void TargetManager::GetAllTargets(
-    std::vector<const Target*>* all_targets) const {
-  base::AutoLock lock(build_settings_->item_tree().lock());
-
-  std::vector<const Item*> all_items;
-  build_settings_->item_tree().GetAllItemsLocked(&all_items);
-  for (size_t i = 0; i < all_items.size(); i++) {
-    const Target* t = all_items[i]->AsTarget();
-    if (t)
-      all_targets->push_back(t);
-  }
-}
diff --git a/tools/gn/target_manager.h b/tools/gn/target_manager.h
deleted file mode 100644
index f7459ff..0000000
--- a/tools/gn/target_manager.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef TOOLS_GN_TARGET_MANAGER_H_
-#define TOOLS_GN_TARGET_MANAGER_H_
-
-#include <set>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/containers/hash_tables.h"
-#include "base/synchronization/lock.h"
-#include "tools/gn/target.h"
-
-class BuildSettings;
-class Err;
-class ItemTree;
-class LocationRange;
-class ToolchainManager;
-class Value;
-
-// Manages all the targets in the system. This integrates with the ItemTree
-// to manage the target-specific rules and creation.
-//
-// This class is threadsafe.
-class TargetManager {
- public:
-  explicit TargetManager(const BuildSettings* settings);
-  ~TargetManager();
-
-  // Gets a reference to a named target. The given target name is created if
-  // it doesn't exist.
-  //
-  // The label should be fully specified in that it should include an
-  // explicit toolchain.
-  //
-  // |specified_from_here| should indicate the dependency or the target
-  // generator causing this access for error message generation.
-  //
-  // |dep_from| should be set when a target is getting a dep that it depends
-  // on. |dep_from| indicates the target that specified the dependency. It
-  // will be used to track outstanding dependencies so we can know when the
-  // target and all of its dependencies are complete. It should be null when
-  // getting a target for other reasons.
-  //
-  // On failure, |err| will be set.
-  //
-  // The returned pointer must not be dereferenced until it's generated, since
-  // it could be being generated on another thread.
-  Target* GetTarget(const Label& label,
-                    const LocationRange& specified_from_here,
-                    Target* dep_from,
-                    Err* err);
-
-  // Called by a target when it has been loaded from the .gin file. Its
-  // dependencies may or may not be resolved yet.
-  bool TargetGenerationComplete(const Label& label, Err* err);
-
-  // Returns a list of all targets.
-  void GetAllTargets(std::vector<const Target*>* all_targets) const;
-
- private:
-  const BuildSettings* build_settings_;
-
-  DISALLOW_COPY_AND_ASSIGN(TargetManager);
-};
-
-#endif  // TOOLS_GN_TARGET_MANAGER_H
diff --git a/tools/gn/target_manager_unittest.cc b/tools/gn/target_manager_unittest.cc
deleted file mode 100644
index a1a3ad2..0000000
--- a/tools/gn/target_manager_unittest.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "tools/gn/err.h"
-#include "tools/gn/settings.h"
-#include "tools/gn/target_manager.h"
-#include "tools/gn/value.h"
-
-/* TODO(brettw) make this compile again
-namespace {
-
-class TestTargetManagerDelegate : public TargetManager::Delegate {
- public:
-  TestTargetManagerDelegate() {}
-
-  virtual bool ScheduleInvocation(ToolchainManager* toolchain_manager,
-                                  const LocationRange& origin,
-                                  const Label& toolchain_name,
-                                  const SourceDir& dir,
-                                  Err* err) OVERRIDE {
-    invokes.push_back(dir.value());
-    return true;
-  }
-  virtual void ScheduleTargetFileWrite(const Target* target) {
-    writes.push_back(target);
-  }
-
-  std::vector<std::string> invokes;
-  std::vector<const Target*> writes;
-};
-
-}  // namespace
-
-TEST(TargetManager, ResolveDeps) {
-  TestTargetManagerDelegate ttmd;
-  BuildSettings build_settings(&ttmd);
-
-  TargetManager& target_manager = build_settings.target_manager();
-
-  SourceDir tc_dir("/chrome/");
-  std::string tc_name("toolchain");
-
-  // Get a root target. This should not invoke anything.
-  Err err;
-  Label chromelabel(SourceDir("/chrome/"), "chrome", tc_dir, tc_name);
-  Target* chrome = target_manager.GetTarget(
-      chromelabel, LocationRange(), NULL, &err);
-  EXPECT_EQ(0u, ttmd.invokes.size());
-
-  // Declare it has a dependency on content1 and 2. We should get one
-  // invocation of the content build file.
-  Label content1label(SourceDir("/content/"), "content1", tc_dir, tc_name);
-  Target* content1 = target_manager.GetTarget(
-      content1label, LocationRange(), chrome, &err);
-  EXPECT_EQ(1u, ttmd.invokes.size());
-
-  Label content2label(SourceDir("/content/"), "content2", tc_dir, tc_name);
-  Target* content2 = target_manager.GetTarget(
-      content2label, LocationRange(), chrome, &err);
-  EXPECT_EQ(2u, ttmd.invokes.size());
-
-  // Declare chrome has a depdency on base, this should load it.
-  Label baselabel(SourceDir("/base/"), "base", tc_dir, tc_name);
-  Target* base1 = target_manager.GetTarget(
-      baselabel, LocationRange(), chrome, &err);
-  EXPECT_EQ(3u, ttmd.invokes.size());
-
-  // Declare content1 has a dependency on base.
-  Target* base2 = target_manager.GetTarget(
-      baselabel, LocationRange(), content1, &err);
-  EXPECT_EQ(3u, ttmd.invokes.size());
-  EXPECT_EQ(base1, base2);
-
-  // Mark content1 and chrome as done. They have unresolved depdendencies so
-  // shouldn't be written out yet.
-  target_manager.TargetGenerationComplete(content1label);
-  target_manager.TargetGenerationComplete(chromelabel);
-  EXPECT_EQ(0u, ttmd.writes.size());
-
-  // Mark content2 as done. It has no dependencies so should be written.
-  target_manager.TargetGenerationComplete(content2label);
-  ASSERT_EQ(1u, ttmd.writes.size());
-  EXPECT_EQ(content2label, ttmd.writes[0]->label());
-
-  // Mark base as complete. It should have caused itself, content1 and then
-  // chrome to be written.
-  target_manager.TargetGenerationComplete(baselabel);
-  ASSERT_EQ(4u, ttmd.writes.size());
-  EXPECT_EQ(baselabel, ttmd.writes[1]->label());
-  EXPECT_EQ(content1label, ttmd.writes[2]->label());
-  EXPECT_EQ(chromelabel, ttmd.writes[3]->label());
-}
-*/
diff --git a/tools/gn/test_with_scope.cc b/tools/gn/test_with_scope.cc
index e149e92..97eb2fb 100644
--- a/tools/gn/test_with_scope.cc
+++ b/tools/gn/test_with_scope.cc
@@ -12,7 +12,7 @@
   build_settings_.SetBuildDir(SourceDir("//out/Debug/"));
 
   settings_.set_toolchain_label(toolchain_.label());
-  settings_.set_is_default(true);
+  settings_.set_default_toolchain_label(toolchain_.label());
 }
 
 TestWithScope::~TestWithScope() {
diff --git a/tools/gn/toolchain_manager.cc b/tools/gn/toolchain_manager.cc
deleted file mode 100644
index 4edf212..0000000
--- a/tools/gn/toolchain_manager.cc
+++ /dev/null
@@ -1,593 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "tools/gn/toolchain_manager.h"
-
-#include <set>
-
-#include "base/bind.h"
-#include "build/build_config.h"
-#include "tools/gn/err.h"
-#include "tools/gn/item.h"
-#include "tools/gn/item_node.h"
-#include "tools/gn/item_tree.h"
-#include "tools/gn/parse_tree.h"
-#include "tools/gn/scheduler.h"
-#include "tools/gn/scope.h"
-#include "tools/gn/scope_per_file_provider.h"
-#include "tools/gn/trace.h"
-
-// How toolchain loading works
-// ---------------------------
-// When we start loading a build, we'll load the build config file and that
-// will call set_default_toolchain. We'll schedule a load of the file
-// containing the default toolchain definition, and can do this in parallel
-// with all other build files. Targets will have an implicit dependency on the
-// toolchain so we won't write out any files until we've loaded the toolchain
-// definition.
-//
-// When we see a reference to a target using a different toolchain, it gets
-// more complicated. In this case, the toolchain definition contains arguments
-// to pass into the build config file when it is invoked in the context of that
-// toolchain. As a result, we have to actually see the definition of the
-// toolchain before doing anything else.
-//
-// So when we see a reference to a non-default toolchain we do the following:
-//
-//  1. Schedule a load of the file containing the toolchain definition, if it
-//     isn't loaded already.
-//  2. When the toolchain definition is loaded, we schedule a load of the
-//     build config file in the context of that toolchain. We'll use the
-//     arguments from the toolchain definition to execute it.
-//  3. When the build config is set up, then we can load all of the individual
-//     buildfiles in the context of that config that we require.
-
-namespace {
-
-enum ToolchainState {
-  // Toolchain settings have not requested to be loaded. This means we
-  // haven't seen any targets that require this toolchain yet. This means that
-  // we have seen a toolchain definition, but no targets that use it. Not
-  // loading the settings automatically allows you to define a bunch of
-  // toolchains and potentially not use them without much overhead.
-  TOOLCHAIN_NOT_LOADED,
-
-  // The toolchain definition for non-default toolchains has been scheduled
-  // to be loaded but has not completed. When this is done, we can load the
-  // settings file. This is needed to get the arguments out of the toolchain
-  // definition. This is skipped for the default toolchain which has no
-  // arguments (see summary above).
-  TOOLCHAIN_DEFINITION_LOADING,
-
-  // The settings have been scheduled to be loaded but have not completed.
-  TOOLCHAIN_SETTINGS_LOADING,
-
-  // The settings are done being loaded.
-  TOOLCHAIN_SETTINGS_LOADED
-};
-
-SourceFile DirToBuildFile(const SourceDir& dir) {
-  return SourceFile(dir.value() + "BUILD.gn");
-}
-
-}  // namespace
-
-struct ToolchainManager::Info {
-  Info(const BuildSettings* build_settings,
-       const Label& toolchain_name,
-       const std::string& output_subdir_name)
-      : state(TOOLCHAIN_NOT_LOADED),
-        settings(build_settings, output_subdir_name),
-        toolchain(new Toolchain(&settings, toolchain_name)),
-        toolchain_set(false),
-        toolchain_file_loaded(false),
-        item_node(NULL) {
-    settings.set_toolchain_label(toolchain_name);
-  }
-
-  ~Info() {
-    if (!item_node)  // See toolchain definition for more.
-      delete toolchain;
-  }
-
-  // Makes sure that an ItemNode is created for the toolchain, which lets
-  // targets depend on the (potentially future) loading of the toolchain.
-  //
-  // We can't always do this at the beginning since when doing the default
-  // build config, we don't know the toolchain name yet. We also need to go
-  // through some effort to avoid doing this inside the toolchain manager's
-  // lock (to avoid holding two locks at once).
-  void EnsureItemNode() {
-    if (!item_node) {
-      ItemTree& tree = settings.build_settings()->item_tree();
-      item_node = new ItemNode(toolchain);
-      tree.AddNodeLocked(item_node);
-    }
-  }
-
-  ToolchainState state;
-
-  // The first place in the build that we saw a reference for this toolchain.
-  // This allows us to report errors if it can't be loaded and blame some
-  // reasonable place of the code. This will be empty for the default toolchain.
-  LocationRange specified_from;
-
-  // When the state is TOOLCHAIN_SETTINGS_LOADED, the settings should be
-  // considered read-only and can be read without locking. Otherwise, they
-  // should not be accessed at all except to load them (which can therefore
-  // also be done outside of the lock). This works as long as the state flag
-  // is only ever read or written inside the lock.
-  Settings settings;
-
-  // When we create an item node, this pointer will be owned by that node
-  // so it's lifetime is managed by the dependency graph. Before we've created
-  // the ItemNode, this class has to takre responsibility for this pointer.
-  Toolchain* toolchain;
-  bool toolchain_set;
-  LocationRange toolchain_definition_location;
-
-  // Set when the file corresponding to the toolchain definition is loaded.
-  // This will normally be set right after "toolchain_set". However, if the
-  // toolchain definition is missing, the file might be marked loaded but the
-  // toolchain definition could still be unset.
-  bool toolchain_file_loaded;
-
-  // While state == TOOLCHAIN_SETTINGS_LOADING || TOOLCHAIN_DEFINITION_LOADING,
-  // this will collect all scheduled invocations using this toolchain. They'll
-  // be issued once the settings file has been interpreted.
-  //
-  // The map maps the source file to "some" location it was invoked from (so
-  // we can give good error messages). It does NOT map to the root of the
-  // file to be invoked (the file still needs loading). This will be NULL
-  // for internally invoked files.
-  typedef std::map<SourceFile, LocationRange> ScheduledInvocationMap;
-  ScheduledInvocationMap scheduled_invocations;
-
-  // Tracks all scheduled and executed invocations for this toolchain. This
-  // is used to avoid invoking a file more than once for a toolchain.
-  std::set<SourceFile> all_invocations;
-
-  // Filled in by EnsureItemNode, see that for more.
-  ItemNode* item_node;
-};
-
-ToolchainManager::ToolchainManager(const BuildSettings* build_settings)
-    : build_settings_(build_settings) {
-}
-
-ToolchainManager::~ToolchainManager() {
-  for (ToolchainMap::iterator i = toolchains_.begin();
-       i != toolchains_.end(); ++i)
-    delete i->second;
-  toolchains_.clear();
-}
-
-void ToolchainManager::StartLoadingUnlocked(const SourceFile& build_file_name) {
-  // How the default build config works: Initially we don't have a toolchain
-  // name to call the settings for the default build config. So we create one
-  // with an empty toolchain name and execute the default build config file.
-  // When that's done, we'll go and fix up the name to the default build config
-  // that the script set.
-  base::AutoLock lock(GetLock());
-  Err err;
-  Info* info = LoadNewToolchainLocked(LocationRange(), Label(), &err);
-  if (err.has_error())
-    g_scheduler->FailWithError(err);
-  CHECK(info);
-  info->scheduled_invocations[build_file_name] = LocationRange();
-  info->all_invocations.insert(build_file_name);
-
-  if (!ScheduleBuildConfigLoadLocked(info, true, &err))
-    g_scheduler->FailWithError(err);
-}
-
-const Settings* ToolchainManager::GetSettingsForToolchainLocked(
-    const LocationRange& from_here,
-    const Label& toolchain_name,
-    Err* err) {
-  GetLock().AssertAcquired();
-  ToolchainMap::iterator found = toolchains_.find(toolchain_name);
-  Info* info = NULL;
-  if (found == toolchains_.end()) {
-    info = LoadNewToolchainLocked(from_here, toolchain_name, err);
-    if (!info)
-      return NULL;
-  } else {
-    info = found->second;
-  }
-  info->EnsureItemNode();
-
-  return &info->settings;
-}
-
-const Toolchain* ToolchainManager::GetToolchainDefinitionUnlocked(
-    const Label& toolchain_name) {
-  base::AutoLock lock(GetLock());
-  ToolchainMap::iterator found = toolchains_.find(toolchain_name);
-  if (found == toolchains_.end() || !found->second->toolchain_set)
-    return NULL;
-
-  // Since we don't allow defining a toolchain more than once, we know that
-  // once it's set it won't be mutated, so we can safely return this pointer
-  // for reading outside the lock.
-  return found->second->toolchain;
-}
-
-bool ToolchainManager::SetDefaultToolchainUnlocked(
-    const Label& default_toolchain,
-    const LocationRange& defined_here,
-    Err* err) {
-  base::AutoLock lock(GetLock());
-  if (!default_toolchain_.is_null()) {
-    *err = Err(defined_here, "Default toolchain already set.");
-    err->AppendSubErr(Err(default_toolchain_defined_here_,
-                          "Previously defined here.",
-                          "You can only set this once."));
-    return false;
-  }
-
-  if (default_toolchain.is_null()) {
-    *err = Err(defined_here, "Bad default toolchain name.",
-        "You can't set the default toolchain name to nothing.");
-    return false;
-  }
-  if (!default_toolchain.toolchain_dir().is_null() ||
-      !default_toolchain.toolchain_name().empty()) {
-    *err = Err(defined_here, "Toolchain name has toolchain.",
-        "You can't specify a toolchain (inside the parens) for a toolchain "
-        "name. I got:\n" + default_toolchain.GetUserVisibleName(true));
-    return false;
-  }
-
-  default_toolchain_ = default_toolchain;
-  default_toolchain_defined_here_ = defined_here;
-  return true;
-}
-
-Label ToolchainManager::GetDefaultToolchainUnlocked() const {
-  base::AutoLock lock(GetLock());
-  return default_toolchain_;
-}
-
-bool ToolchainManager::SetToolchainDefinitionLocked(
-    const Toolchain& tc,
-    const LocationRange& defined_from,
-    Err* err) {
-  GetLock().AssertAcquired();
-
-  ToolchainMap::iterator found = toolchains_.find(tc.label());
-  Info* info = NULL;
-  if (found == toolchains_.end()) {
-    // New toolchain.
-    info = LoadNewToolchainLocked(defined_from, tc.label(), err);
-    if (!info)
-      return false;
-  } else {
-    // It's important to preserve the exact Toolchain object in our tree since
-    // it will be in the ItemTree and targets may have dependencies on it.
-    info = found->second;
-  }
-
-  // The labels should match or else we're setting the wrong one!
-  CHECK(info->toolchain->label() == tc.label());
-
-  // Save the toolchain. We can just overwrite our definition.
-  *info->toolchain = tc;
-
-  if (info->toolchain_set) {
-    *err = Err(defined_from, "Duplicate toolchain definition.");
-    err->AppendSubErr(Err(
-        info->toolchain_definition_location,
-        "Previously defined here.",
-        "A toolchain can only be defined once. One tricky way that this could\n"
-        "happen is if your definition is itself in a file that's interpreted\n"
-        "under different toolchains, which would result in multiple\n"
-        "definitions as the file is loaded multiple times. So be sure your\n"
-        "toolchain definitions are in files that either don't define any\n"
-        "targets (probably best) or at least don't contain targets executed\n"
-        "with more than one toolchain."));
-    return false;
-  }
-
-  info->EnsureItemNode();
-
-  info->toolchain_set = true;
-  info->toolchain_definition_location = defined_from;
-  return true;
-}
-
-bool ToolchainManager::ScheduleInvocationLocked(
-    const LocationRange& specified_from,
-    const Label& toolchain_name,
-    const SourceDir& dir,
-    Err* err) {
-  GetLock().AssertAcquired();
-  SourceFile build_file(DirToBuildFile(dir));
-
-  // If there's no specified toolchain name, use the default.
-  ToolchainMap::iterator found;
-  if (toolchain_name.is_null())
-    found = toolchains_.find(default_toolchain_);
-  else
-    found = toolchains_.find(toolchain_name);
-
-  Info* info = NULL;
-  if (found == toolchains_.end()) {
-    // New toolchain.
-    info = LoadNewToolchainLocked(specified_from, toolchain_name, err);
-    if (!info)
-      return false;
-  } else {
-    // Use existing one.
-    info = found->second;
-    if (info->all_invocations.find(build_file) !=
-        info->all_invocations.end()) {
-      // We've already seen this source file for this toolchain, don't need
-      // to do anything.
-      return true;
-    }
-  }
-
-  info->all_invocations.insert(build_file);
-
-  switch (info->state) {
-    case TOOLCHAIN_NOT_LOADED:
-      // Toolchain needs to be loaded. Start loading it and push this buildfile
-      // on the wait queue. The actual toolchain build file will have been
-      // scheduled to be loaded by LoadNewToolchainLocked() above, so we just
-      // need to request that the build settings be loaded when that toolchain
-      // file is done executing (recall toolchain files are executed in the
-      // context of the default toolchain, which is why we need to do the extra
-      // Info lookup in the make_pair).
-      DCHECK(!default_toolchain_.is_null());
-      pending_build_config_map_[
-              std::make_pair(DirToBuildFile(toolchain_name.dir()),
-                             toolchains_[default_toolchain_])] =
-          info;
-      info->scheduled_invocations[build_file] = specified_from;
-
-      // Transition to the loading state.
-      info->specified_from = specified_from;
-      info->state = TOOLCHAIN_DEFINITION_LOADING;
-      return true;
-
-    case TOOLCHAIN_DEFINITION_LOADING:
-    case TOOLCHAIN_SETTINGS_LOADING:
-      // Toolchain is in the process of loading, push this buildfile on the
-      // wait queue to run when the config is ready.
-      info->scheduled_invocations[build_file] = specified_from;
-      return true;
-
-    case TOOLCHAIN_SETTINGS_LOADED:
-      // Everything is ready, just schedule the build file to load.
-      return ScheduleBackgroundInvoke(info, specified_from, build_file, err);
-
-    default:
-      NOTREACHED();
-      return false;
-  }
-}
-
-// static
-std::string ToolchainManager::ToolchainToOutputSubdir(
-    const Label& toolchain_name) {
-  // For now just assume the toolchain name is always a valid dir name. We may
-  // want to clean up the in the future.
-  return toolchain_name.name();
-}
-
-ToolchainManager::Info* ToolchainManager::LoadNewToolchainLocked(
-    const LocationRange& specified_from,
-    const Label& toolchain_name,
-    Err* err) {
-  GetLock().AssertAcquired();
-  Info* info = new Info(build_settings_,
-                        toolchain_name,
-                        ToolchainToOutputSubdir(toolchain_name));
-
-  toolchains_[toolchain_name] = info;
-
-  // Invoke the file containing the toolchain definition so that it gets
-  // defined. The default one (label is empty) will be done spearately.
-  if (!toolchain_name.is_null()) {
-    // The default toolchain should be specified whenever we're requesting
-    // another one. This is how we know under what context we should execute
-    // the invoke for the toolchain file.
-    CHECK(!default_toolchain_.is_null());
-    ScheduleInvocationLocked(specified_from, default_toolchain_,
-                             toolchain_name.dir(), err);
-  }
-  return info;
-}
-
-void ToolchainManager::FixupDefaultToolchainLocked() {
-  // Now that we've run the default build config, we should know the
-  // default toolchain name. Fix up our reference.
-  // See Start() for more.
-  GetLock().AssertAcquired();
-  if (default_toolchain_.is_null()) {
-    g_scheduler->FailWithError(Err(Location(),
-        "Default toolchain not set.",
-        "Your build config file \"" +
-        build_settings_->build_config_file().value() +
-        "\"\ndid not call set_default_toolchain(). This is needed so "
-        "I know how to actually\ncompile your code."));
-    return;
-  }
-
-  ToolchainMap::iterator old_default = toolchains_.find(Label());
-  CHECK(old_default != toolchains_.end());
-  Info* info = old_default->second;
-  toolchains_[default_toolchain_] = info;
-  toolchains_.erase(old_default);
-
-  // Toolchain should not have been loaded in the build config file.
-  CHECK(!info->toolchain_set);
-
-  // We need to set the toolchain label now that we know it. There's no way
-  // to set the label, but we can assign the toolchain to a new one. Loading
-  // the build config can not change the toolchain, so we won't be overwriting
-  // anything useful.
-  *info->toolchain = Toolchain(&info->settings, default_toolchain_);
-  info->settings.set_is_default(true);
-  info->settings.set_toolchain_label(default_toolchain_);
-  info->EnsureItemNode();
-
-  // The default toolchain is loaded in greedy mode so all targets we
-  // encounter are generated. Non-default toolchain settings stay in non-greedy
-  // so we only generate the minimally required set.
-  info->settings.set_greedy_target_generation(true);
-
-  // Schedule a load of the toolchain build file.
-  Err err;
-  ScheduleInvocationLocked(LocationRange(), default_toolchain_,
-                           default_toolchain_.dir(), &err);
-  if (err.has_error())
-    g_scheduler->FailWithError(err);
-}
-
-bool ToolchainManager::ScheduleBackgroundInvoke(
-    Info* info,
-    const LocationRange& specified_from,
-    const SourceFile& build_file,
-    Err* err) {
-  g_scheduler->IncrementWorkCount();
-  if (!g_scheduler->input_file_manager()->AsyncLoadFile(
-           specified_from, build_settings_, build_file,
-           base::Bind(&ToolchainManager::BackgroundInvoke,
-                      base::Unretained(this), info, build_file),
-           err)) {
-    g_scheduler->DecrementWorkCount();
-    return false;
-  }
-  return true;
-}
-
-bool ToolchainManager::ScheduleBuildConfigLoadLocked(Info* info,
-                                                     bool is_default,
-                                                     Err* err) {
-  GetLock().AssertAcquired();
-
-  g_scheduler->IncrementWorkCount();
-  if (!g_scheduler->input_file_manager()->AsyncLoadFile(
-           info->specified_from, build_settings_,
-           build_settings_->build_config_file(),
-           base::Bind(&ToolchainManager::BackgroundLoadBuildConfig,
-                      base::Unretained(this), info, is_default),
-           err)) {
-    g_scheduler->DecrementWorkCount();
-    return false;
-  }
-  info->state = TOOLCHAIN_SETTINGS_LOADING;
-  return true;
-}
-
-void ToolchainManager::BackgroundLoadBuildConfig(Info* info,
-                                                 bool is_default,
-                                                 const ParseNode* root) {
-  // Danger: No early returns without decrementing the work count.
-  if (root && !g_scheduler->is_failed()) {
-    // Nobody should be accessing settings at this point other than us since we
-    // haven't marked it loaded, so we can do it outside the lock.
-    Scope* base_config = info->settings.base_config();
-    base_config->set_source_dir(SourceDir("//"));
-
-    info->settings.build_settings()->build_args().SetupRootScope(
-        base_config, info->toolchain->args());
-
-    base_config->SetProcessingBuildConfig();
-    if (is_default)
-      base_config->SetProcessingDefaultBuildConfig();
-
-    ScopedTrace trace(TraceItem::TRACE_FILE_EXECUTE,
-        info->settings.build_settings()->build_config_file().value());
-    trace.SetToolchain(info->settings.toolchain_label());
-
-    const BlockNode* root_block = root->AsBlock();
-    Err err;
-    root_block->ExecuteBlockInScope(base_config, &err);
-
-    trace.Done();
-
-    base_config->ClearProcessingBuildConfig();
-    if (is_default)
-      base_config->ClearProcessingDefaultBuildConfig();
-
-    if (err.has_error()) {
-      g_scheduler->FailWithError(err);
-    } else {
-      // Base config processing succeeded.
-      Info::ScheduledInvocationMap schedule_these;
-      {
-        base::AutoLock lock(GetLock());
-        schedule_these.swap(info->scheduled_invocations);
-        info->state = TOOLCHAIN_SETTINGS_LOADED;
-        if (is_default)
-          FixupDefaultToolchainLocked();
-      }
-
-      // Schedule build files waiting on this settings. There can be many so we
-      // want to load them in parallel on the pool.
-      for (Info::ScheduledInvocationMap::iterator i = schedule_these.begin();
-           i != schedule_these.end() && !g_scheduler->is_failed(); ++i) {
-        if (!ScheduleBackgroundInvoke(info, i->second, i->first, &err)) {
-          g_scheduler->FailWithError(err);
-          break;
-        }
-      }
-    }
-  }
-  g_scheduler->DecrementWorkCount();
-}
-
-void ToolchainManager::BackgroundInvoke(const Info* info,
-                                        const SourceFile& file_name,
-                                        const ParseNode* root) {
-  if (root && !g_scheduler->is_failed()) {
-    if (g_scheduler->verbose_logging()) {
-      g_scheduler->Log("Running", file_name.value() + " with toolchain " +
-                       info->toolchain->label().GetUserVisibleName(false));
-    }
-
-    Scope our_scope(info->settings.base_config());
-    ScopePerFileProvider per_file_provider(&our_scope);
-    our_scope.set_source_dir(file_name.GetDir());
-
-    ScopedTrace trace(TraceItem::TRACE_FILE_EXECUTE, file_name.value());
-    trace.SetToolchain(info->settings.toolchain_label());
-
-    Err err;
-    root->Execute(&our_scope, &err);
-    if (err.has_error())
-      g_scheduler->FailWithError(err);
-
-    trace.Done();
-
-    {
-      // Check to see if any build config invocations depend on this file and
-      // invoke them.
-      base::AutoLock lock(GetLock());
-      BuildConfigInvokeMap::iterator found_file =
-          pending_build_config_map_.find(std::make_pair(file_name, info));
-      if (found_file != pending_build_config_map_.end()) {
-        // The toolchain state should be waiting on the definition, which
-        // should be the thing we just loaded.
-        Info* info_to_load = found_file->second;
-        DCHECK(info_to_load->state == TOOLCHAIN_DEFINITION_LOADING);
-        DCHECK(!info_to_load->toolchain_file_loaded);
-        info_to_load->toolchain_file_loaded = true;
-
-        if (!ScheduleBuildConfigLoadLocked(info_to_load, false, &err))
-          g_scheduler->FailWithError(err);
-        pending_build_config_map_.erase(found_file);
-      }
-    }
-  }
-
-  g_scheduler->DecrementWorkCount();
-}
-
-base::Lock& ToolchainManager::GetLock() const {
-  return build_settings_->item_tree().lock();
-}
diff --git a/tools/gn/toolchain_manager.h b/tools/gn/toolchain_manager.h
deleted file mode 100644
index 9e75f33..0000000
--- a/tools/gn/toolchain_manager.h
+++ /dev/null
@@ -1,170 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef TOOLS_GN_TOOLCHAIN_MANAGER_H_
-#define TOOLS_GN_TOOLCHAIN_MANAGER_H_
-
-#include <map>
-
-#include "base/basictypes.h"
-#include "base/synchronization/lock.h"
-#include "tools/gn/label.h"
-#include "tools/gn/location.h"
-#include "tools/gn/source_file.h"
-#include "tools/gn/toolchain.h"
-
-class Err;
-class BuildSettings;
-class ParseNode;
-class Settings;
-
-// The toolchain manager manages the mapping of toolchain names to the
-// settings and toolchain object. It also loads build files in the context of a
-// toolchain context of a toolchain, and manages running the build config
-// script when necessary.
-//
-// This class uses the lock from the item tree to manage threadsafety. The
-// functions requiring this lock to be held are named "Locked" to make this
-// more clear. The "Unlocked" versions will acquire the lock themselves so will
-// break if you call it while locked. (The rationale behind which is which is
-// just based on the needs of the callers, so it can be changed.) There are two
-// reasons for this:
-//
-// The first is that when resolving a target, we do a bunch of script
-// stuff (slow) and then lookup the target, config, and toolchain dependencies
-// based on that. The options are to do a lock around each dependency lookup
-// or do a lock around the entire operation. Given that there's not a huge
-// amount of work, the "big lock" approach is likely a bit better since it
-// avoids lots of locking overhead.
-//
-// The second reason is that if we had a separate lock here, we would need to
-// lock around creating a new toolchain. But creating a new toolchain involves
-// adding it to the item tree, and this needs to be done atomically to prevent
-// other threads from seeing a partially initialized toolchain. This sets up
-// having deadlock do to acquiring multiple locks, or recursive locking
-// problems.
-class ToolchainManager {
- public:
-  ToolchainManager(const BuildSettings* build_settings);
-  ~ToolchainManager();
-
-  // At the very beginning of processing, this begins loading build files.
-  // This will scheduler loadin the default build config and the given build
-  // file in that context, going out from there.
-  //
-  // This returns immediately, you need to run the Scheduler to actually
-  // process anything. It's assumed this function is called on the main thread
-  // before doing anything, so it does not need locking.
-  void StartLoadingUnlocked(const SourceFile& build_file_name);
-
-  // Returns the settings object for a given toolchain. This does not
-  // schedule loading the given toolchain if it's not loaded yet: you actually
-  // need to invoke a target with that toolchain to get that.
-  //
-  // On error, returns NULL and sets the error.
-  const Settings* GetSettingsForToolchainLocked(const LocationRange& from_here,
-                                                const Label& toolchain_name,
-                                                Err* err);
-
-  // Returns the toolchain definition or NULL if the toolchain hasn't been
-  // defined yet.
-  const Toolchain* GetToolchainDefinitionUnlocked(const Label& toolchain_name);
-
-  // Sets the default toolchain. If the default toolchain is already set,
-  // this function will return false and fill in the given err.
-  bool SetDefaultToolchainUnlocked(const Label& dt,
-                                   const LocationRange& defined_from,
-                                   Err* err);
-
-  // Returns the default toolchain name. This will be empty if it hasn't been
-  // set.
-  Label GetDefaultToolchainUnlocked() const;
-
-  // Saves the given named toolchain (the name will be taken from the toolchain
-  // parameter). This will fail and return false if the given toolchain was
-  // already defined. In this case, the given error will be set.
-  bool SetToolchainDefinitionLocked(const Toolchain& tc,
-                                    const LocationRange& defined_from,
-                                    Err* err);
-
-  // Schedules an invocation of the given file under the given toolchain. The
-  // toolchain file will be loaded if necessary. If the toolchain is an is_null
-  // label, the default toolchain will be used.
-  //
-  // The origin should be the node that will be blamed for this invocation if
-  // an error occurs. If a synchronous error occurs, the given error will be
-  // set and it will return false. If an async error occurs, the error will be
-  // sent to the scheduler.
-  bool ScheduleInvocationLocked(const LocationRange& origin,
-                                const Label& toolchain_name,
-                                const SourceDir& dir,
-                                Err* err);
-
- private:
-  struct Info;
-
-  static std::string ToolchainToOutputSubdir(const Label& toolchain_name);
-
-  // Creates a new info struct and saves it in the map. A pointer to the
-  // struct is returned. No loads are scheduled.
-  //
-  // If the label is non-empty, the toolchain will be added to the ItemTree
-  // so that other nodes can depend on it. THe empty label case is for the
-  // default build config file (when the toolchain name isn't known yet). It
-  // will be added later.
-  //
-  // On error, will return NULL and the error will be set.
-  Info* LoadNewToolchainLocked(const LocationRange& specified_from,
-                               const Label& toolchain_name,
-                               Err* err);
-
-  // Fixes up the default toolchain names once they're known when processing
-  // the default build config, or throw an error if the default toolchain
-  // hasn't been set. See the StartLoading() implementation for more.
-  void FixupDefaultToolchainLocked();
-
-  // Schedules the buildfile to be invoked for the given toolchain info. The
-  // toolchain must be already loaded. Can be called with the lock held or not
-  // (it does not use any class vars).
-  bool ScheduleBackgroundInvoke(Info* info,
-                                const LocationRange& specified_from,
-                                const SourceFile& build_file,
-                                Err* err);
-
-  // Schedules the build config file for the given info to be loaded and
-  // invoked. The toolchain definition (for non-default toolchains) should
-  // already be loaded.
-  bool ScheduleBuildConfigLoadLocked(Info* info, bool is_default, Err* err);
-
-  // Invokes the given file for a toolchain with loaded settings. Run on a
-  // background thread asynchronously.
-  void BackgroundInvoke(const Info* info,
-                        const SourceFile& file_name,
-                        const ParseNode* root);
-
-  // Loads the build config file for the given Info.
-  void BackgroundLoadBuildConfig(Info* info,
-                                 bool is_default,
-                                 const ParseNode* root);
-
-  // Returns the lock to use.
-  base::Lock& GetLock() const;
-
-  const BuildSettings* build_settings_;
-
-  // We own the info pointers.
-  typedef std::map<Label, Info*> ToolchainMap;
-  ToolchainMap toolchains_;
-
-  Label default_toolchain_;
-  LocationRange default_toolchain_defined_here_;
-
-  typedef std::map<std::pair<SourceFile, const Info*>, Info*>
-      BuildConfigInvokeMap;
-  BuildConfigInvokeMap pending_build_config_map_;
-
-  DISALLOW_COPY_AND_ASSIGN(ToolchainManager);
-};
-
-#endif  // TOOLS_GN_TOOLCHAIN_MANAGER_H_
diff --git a/tools/gn/trace.cc b/tools/gn/trace.cc
index 429cc71..aa73eba 100644
--- a/tools/gn/trace.cc
+++ b/tools/gn/trace.cc
@@ -134,6 +134,16 @@
   }
 }
 
+ScopedTrace::ScopedTrace(TraceItem::Type t, const Label& label)
+    : item_(NULL),
+      done_(false) {
+  if (trace_log) {
+    item_ = new TraceItem(t, label.GetUserVisibleName(false),
+                          base::PlatformThread::CurrentId());
+    item_->set_begin(base::TimeTicks::HighResNow());
+  }
+}
+
 ScopedTrace::~ScopedTrace() {
   Done();
 }
@@ -190,6 +200,7 @@
         break;
       case TraceItem::TRACE_FILE_LOAD:
       case TraceItem::TRACE_FILE_WRITE:
+      case TraceItem::TRACE_DEFINE_TARGET:
         break;  // Ignore these for the summary.
     }
   }
@@ -212,6 +223,12 @@
 
   std::string quote_buffer;  // Allocate outside loop to prevent reallocationg.
 
+  // Write main thread metadata (assume this is being written on the main
+  // thread).
+  out << "{\"pid\":0,\"tid\":" << base::PlatformThread::CurrentId();
+  out << ",\"ts\":0,\"ph\":\"M\",";
+  out << "\"name\":\"thread_name\",\"args\":{\"name\":\"Main thread\"}},";
+
   std::vector<TraceItem*> events = trace_log->events();
   for (size_t i = 0; i < events.size(); i++) {
     const TraceItem& item = *events[i];
@@ -244,6 +261,8 @@
       case TraceItem::TRACE_SCRIPT_EXECUTE:
         out << "\"script_exec\"";
         break;
+      case TraceItem::TRACE_DEFINE_TARGET:
+        out << "\"define\"";
     }
 
     if (!item.toolchain().empty() || !item.cmdline().empty()) {
diff --git a/tools/gn/trace.h b/tools/gn/trace.h
index dcd8060..b795bf7 100644
--- a/tools/gn/trace.h
+++ b/tools/gn/trace.h
@@ -23,7 +23,8 @@
     TRACE_FILE_PARSE,
     TRACE_FILE_EXECUTE,
     TRACE_FILE_WRITE,
-    TRACE_SCRIPT_EXECUTE
+    TRACE_SCRIPT_EXECUTE,
+    TRACE_DEFINE_TARGET
   };
 
   TraceItem(Type type,
@@ -65,6 +66,7 @@
 class ScopedTrace {
  public:
   ScopedTrace(TraceItem::Type t, const std::string& name);
+  ScopedTrace(TraceItem::Type t, const Label& label);
   ~ScopedTrace();
 
   void SetToolchain(const Label& label);