Roll src/third_party/WebKit bf18a82:a9cee16 (svn 185297:185304)
[chromium-blink-merge.git] / chrome / tools / profile_reset / jtl_compiler.cc
blobffa5ec27b664ca8b4537b8b687cca99071dedd02
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/tools/profile_reset/jtl_compiler.h"
7 #include <limits>
8 #include <map>
9 #include <numeric>
11 #include "base/logging.h"
12 #include "chrome/browser/profile_resetter/jtl_foundation.h"
13 #include "chrome/tools/profile_reset/jtl_parser.h"
15 namespace jtl = jtl_foundation;
17 namespace {
19 // Serializes symbols into byte-code in a streaming manner.
20 class ByteCodeWriter {
21 public:
22 explicit ByteCodeWriter(std::string* output) : output_(output) {}
23 ~ByteCodeWriter() {}
25 void WriteUint8(uint8 value) { output_->push_back(static_cast<char>(value)); }
26 void WriteUint32(uint32 value) {
27 for (int i = 0; i < 4; ++i) {
28 output_->push_back(static_cast<char>(value & 0xFFu));
29 value >>= 8;
32 void WriteOpCode(uint8 op_code) { WriteUint8(op_code); }
33 void WriteHash(const std::string& hash) {
34 CHECK(jtl::Hasher::IsHash(hash));
35 *output_ += hash;
37 void WriteBool(bool value) { WriteUint8(value ? 1u : 0u); }
39 private:
40 std::string* output_;
42 DISALLOW_COPY_AND_ASSIGN(ByteCodeWriter);
45 // Encapsulates meta-data about all instructions, and is capable of transcoding
46 // each instruction from a parsed text-based format to byte-code.
47 class InstructionSet {
48 public:
49 InstructionSet() {
50 // Define each instruction in this list.
51 // Note:
52 // - Instructions ending in "hash" will write their 'HashString' arguments
53 // directly into the byte-code.
54 // - Instructions ending in "hashed" will first hash their 'String'
55 // arguments, and will write this hash to the byte-code.
56 Add(Instruction("go", jtl::NAVIGATE, Arguments(String)));
57 Add(Instruction("any", jtl::NAVIGATE_ANY, Arguments()));
58 Add(Instruction("back", jtl::NAVIGATE_BACK, Arguments()));
59 Add(Instruction("store_bool", jtl::STORE_BOOL, Arguments(String, Bool)));
60 Add(Instruction("store_hash",
61 jtl::STORE_HASH, Arguments(String, HashString)));
62 Add(Instruction("store_hashed",
63 jtl::STORE_HASH, Arguments(String, String)));
64 Add(Instruction("store_node_bool",
65 jtl::STORE_NODE_BOOL, Arguments(String)));
66 Add(Instruction("store_node_hash",
67 jtl::STORE_NODE_HASH, Arguments(String)));
68 Add(Instruction("store_node_registerable_domain_hash",
69 jtl::STORE_NODE_REGISTERABLE_DOMAIN_HASH,
70 Arguments(String)));
71 Add(Instruction("compare_bool", jtl::COMPARE_NODE_BOOL, Arguments(Bool)));
72 Add(Instruction("compare_hashed",
73 jtl::COMPARE_NODE_HASH, Arguments(String)));
74 Add(Instruction("compare_hashed_not",
75 jtl::COMPARE_NODE_HASH_NOT, Arguments(String)));
76 Add(Instruction("compare_stored_bool",
77 jtl::COMPARE_STORED_BOOL,
78 Arguments(String, Bool, Bool)));
79 Add(Instruction("compare_stored_hashed",
80 jtl::COMPARE_STORED_HASH,
81 Arguments(String, String, String)));
82 Add(Instruction("compare_to_stored_bool",
83 jtl::COMPARE_NODE_TO_STORED_BOOL,
84 Arguments(String)));
85 Add(Instruction("compare_to_stored_hash",
86 jtl::COMPARE_NODE_TO_STORED_HASH,
87 Arguments(String)));
88 Add(Instruction("compare_substring_hashed",
89 jtl::COMPARE_NODE_SUBSTRING,
90 Arguments(StringPattern)));
91 Add(Instruction("break", jtl::STOP_EXECUTING_SENTENCE, Arguments()));
94 JtlCompiler::CompileError::ErrorCode TranscodeInstruction(
95 const std::string& name,
96 const base::ListValue& arguments,
97 bool ends_sentence,
98 const jtl::Hasher& hasher,
99 ByteCodeWriter* target) const {
100 if (instruction_map_.count(name) == 0)
101 return JtlCompiler::CompileError::INVALID_OPERATION_NAME;
102 const Instruction& instruction(instruction_map_.at(name));
103 if (instruction.argument_types.size() != arguments.GetSize())
104 return JtlCompiler::CompileError::INVALID_ARGUMENT_COUNT;
105 target->WriteOpCode(instruction.op_code);
106 for (size_t i = 0; i < arguments.GetSize(); ++i) {
107 switch (instruction.argument_types[i]) {
108 case Bool: {
109 bool value = false;
110 if (!arguments.GetBoolean(i, &value))
111 return JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE;
112 target->WriteBool(value);
113 break;
115 case String: {
116 std::string value;
117 if (!arguments.GetString(i, &value))
118 return JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE;
119 target->WriteHash(hasher.GetHash(value));
120 break;
122 case StringPattern: {
123 std::string value;
124 if (!arguments.GetString(i, &value))
125 return JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE;
126 if (value.empty() ||
127 value.size() > std::numeric_limits<uint32>::max())
128 return JtlCompiler::CompileError::INVALID_ARGUMENT_VALUE;
129 target->WriteHash(hasher.GetHash(value));
130 target->WriteUint32(static_cast<uint32>(value.size()));
131 uint32 pattern_sum = std::accumulate(
132 value.begin(), value.end(), static_cast<uint32>(0u));
133 target->WriteUint32(pattern_sum);
134 break;
136 case HashString: {
137 std::string hash_value;
138 if (!arguments.GetString(i, &hash_value) ||
139 !jtl::Hasher::IsHash(hash_value))
140 return JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE;
141 target->WriteHash(hash_value);
142 break;
144 default:
145 NOTREACHED();
146 return JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE;
149 if (ends_sentence)
150 target->WriteOpCode(jtl::END_OF_SENTENCE);
151 return JtlCompiler::CompileError::ERROR_NONE;
154 private:
155 // The possible types of an operation's argument.
156 enum ArgumentType {
157 None,
158 Bool,
159 String,
160 StringPattern,
161 HashString
164 // Encapsulates meta-data about one instruction.
165 struct Instruction {
166 Instruction() : op_code(jtl::END_OF_SENTENCE) {}
167 Instruction(const char* name,
168 jtl_foundation::OpCodes op_code,
169 const std::vector<ArgumentType>& argument_types)
170 : name(name), op_code(op_code), argument_types(argument_types) {}
172 std::string name;
173 jtl::OpCodes op_code;
174 std::vector<ArgumentType> argument_types;
177 static std::vector<ArgumentType> Arguments(ArgumentType arg1_type = None,
178 ArgumentType arg2_type = None,
179 ArgumentType arg3_type = None) {
180 std::vector<ArgumentType> result;
181 if (arg1_type != None)
182 result.push_back(arg1_type);
183 if (arg2_type != None)
184 result.push_back(arg2_type);
185 if (arg3_type != None)
186 result.push_back(arg3_type);
187 return result;
190 void Add(const Instruction& instruction) {
191 instruction_map_[instruction.name] = instruction;
194 std::map<std::string, Instruction> instruction_map_;
196 DISALLOW_COPY_AND_ASSIGN(InstructionSet);
199 } // namespace
201 bool JtlCompiler::Compile(const std::string& source_code,
202 const std::string& hash_seed,
203 std::string* output_bytecode,
204 CompileError* error_details) {
205 DCHECK(output_bytecode);
206 InstructionSet instruction_set;
207 ByteCodeWriter bytecode_writer(output_bytecode);
208 jtl::Hasher hasher(hash_seed);
210 std::string compacted_source_code;
211 std::vector<size_t> newline_indices;
212 size_t mismatched_quotes_line;
213 if (!JtlParser::RemoveCommentsAndAllWhitespace(source_code,
214 &compacted_source_code,
215 &newline_indices,
216 &mismatched_quotes_line)) {
217 if (error_details) {
218 error_details->context = ""; // No meaningful intra-line context here.
219 error_details->line_number = mismatched_quotes_line;
220 error_details->error_code = CompileError::MISMATCHED_DOUBLE_QUOTES;
222 return false;
225 JtlParser parser(compacted_source_code, newline_indices);
226 while (!parser.HasFinished()) {
227 std::string operation_name;
228 base::ListValue arguments;
229 bool ends_sentence = false;
230 if (!parser.ParseNextOperation(
231 &operation_name, &arguments, &ends_sentence)) {
232 if (error_details) {
233 error_details->context = parser.GetLastContext();
234 error_details->line_number = parser.GetLastLineNumber();
235 error_details->error_code = CompileError::PARSING_ERROR;
237 return false;
239 CompileError::ErrorCode error_code = instruction_set.TranscodeInstruction(
240 operation_name, arguments, ends_sentence, hasher, &bytecode_writer);
241 if (error_code != CompileError::ERROR_NONE) {
242 if (error_details) {
243 error_details->context = parser.GetLastContext();
244 error_details->line_number = parser.GetLastLineNumber();
245 error_details->error_code = error_code;
247 return false;
251 return true;