aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShinichiro Hamaji <shinichiro.hamaji@gmail.com>2016-02-17 17:19:21 +0900
committerShinichiro Hamaji <shinichiro.hamaji@gmail.com>2016-02-17 17:19:21 +0900
commit92a4738218523292a0cec0310023eed194025f24 (patch)
tree384f420b0b9c8254be840caeb22d4b8576522db2
parent121165ed878d844662a25d5ee3b95ab1ceaddca2 (diff)
downloadkati-92a4738218523292a0cec0310023eed194025f24.tar.gz
[C++] Add a fast path for interning lhs of assignments
-rw-r--r--eval.cc2
-rw-r--r--expr.cc1
-rw-r--r--expr.h2
-rw-r--r--stmt.cc13
-rw-r--r--stmt.h9
5 files changed, 26 insertions, 1 deletions
diff --git a/eval.cc b/eval.cc
index 3dfc0e6..be4bb34 100644
--- a/eval.cc
+++ b/eval.cc
@@ -96,7 +96,7 @@ Var* Evaluator::EvalRHS(Symbol lhs, Value* rhs_v, StringPiece orig_rhs,
void Evaluator::EvalAssign(const AssignStmt* stmt) {
loc_ = stmt->loc();
last_rule_ = NULL;
- Symbol lhs = Intern(stmt->lhs->Eval(this));
+ Symbol lhs = stmt->GetLhsSymbol(this);
if (lhs.empty())
Error("*** empty variable name.");
Var* rhs = EvalRHS(lhs, stmt->rhs, stmt->orig_rhs, stmt->op,
diff --git a/expr.cc b/expr.cc
index 3da740e..a629352 100644
--- a/expr.cc
+++ b/expr.cc
@@ -63,6 +63,7 @@ class Literal : public Value {
}
virtual bool IsLiteral() const override { return true; }
+ virtual StringPiece GetLiteralValueUnsafe() const { return s_; }
virtual string DebugString_() const override {
return s_.as_string();
diff --git a/expr.h b/expr.h
index e479ed8..fdd6d36 100644
--- a/expr.h
+++ b/expr.h
@@ -42,6 +42,8 @@ class Value : public Evaluable {
virtual Value* Compact() { return this; }
virtual bool IsLiteral() const { return false; }
+ // Only safe after IsLiteral() returns true.
+ virtual StringPiece GetLiteralValueUnsafe() const { return ""; }
string DebugString() const;
diff --git a/stmt.cc b/stmt.cc
index 1abab32..155e0cd 100644
--- a/stmt.cc
+++ b/stmt.cc
@@ -55,6 +55,19 @@ string AssignStmt::DebugString() const {
opstr, dirstr, LOCF(loc()));
}
+Symbol AssignStmt::GetLhsSymbol(Evaluator* ev) const {
+ if (!lhs->IsLiteral()) {
+ string buf;
+ lhs->Eval(ev, &buf);
+ return Intern(buf);
+ }
+
+ if (!lhs_sym_cache_.IsValid()) {
+ lhs_sym_cache_ = Intern(lhs->GetLiteralValueUnsafe());
+ }
+ return lhs_sym_cache_;
+}
+
string CommandStmt::DebugString() const {
return StringPrintf("CommandStmt(%s, loc=%s:%d)",
expr->DebugString().c_str(), LOCF(loc()));
diff --git a/stmt.h b/stmt.h
index 4d4c5eb..3b6feeb 100644
--- a/stmt.h
+++ b/stmt.h
@@ -20,6 +20,7 @@
#include "loc.h"
#include "string_piece.h"
+#include "symtab.h"
using namespace std;
@@ -85,11 +86,19 @@ struct AssignStmt : public Stmt {
AssignOp op;
AssignDirective directive;
+ AssignStmt()
+ : lhs_sym_cache_(Symbol::IsUninitialized{}) {
+ }
virtual ~AssignStmt();
virtual void Eval(Evaluator* ev) const;
virtual string DebugString() const;
+
+ Symbol GetLhsSymbol(Evaluator* ev) const;
+
+ private:
+ mutable Symbol lhs_sym_cache_;
};
struct CommandStmt : public Stmt {