OLD | NEW |
| (Empty) |
1 // Copyright 2015 the V8 project 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. | |
4 | |
5 #include "src/v8.h" | |
6 | |
7 // Required to get M_E etc. in MSVC. | |
8 #if defined(_WIN32) | |
9 #define _USE_MATH_DEFINES | |
10 #endif | |
11 #include <math.h> | |
12 | |
13 #include "src/wasm/asm-wasm-builder.h" | |
14 #include "src/wasm/switch-logic.h" | |
15 #include "src/wasm/wasm-macro-gen.h" | |
16 #include "src/wasm/wasm-opcodes.h" | |
17 | |
18 #include "src/ast/ast.h" | |
19 #include "src/ast/scopes.h" | |
20 #include "src/codegen.h" | |
21 #include "src/type-cache.h" | |
22 | |
23 namespace v8 { | |
24 namespace internal { | |
25 namespace wasm { | |
26 | |
27 #define RECURSE(call) \ | |
28 do { \ | |
29 DCHECK(!HasStackOverflow()); \ | |
30 call; \ | |
31 if (HasStackOverflow()) return; \ | |
32 } while (false) | |
33 | |
34 enum AsmScope { kModuleScope, kInitScope, kFuncScope, kExportScope }; | |
35 | |
36 struct ForeignVariable { | |
37 Handle<Name> name; | |
38 Variable* var; | |
39 LocalType type; | |
40 }; | |
41 | |
42 class AsmWasmBuilderImpl : public AstVisitor { | |
43 public: | |
44 AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, FunctionLiteral* literal, | |
45 AsmTyper* typer) | |
46 : local_variables_(base::HashMap::PointersMatch, | |
47 ZoneHashMap::kDefaultHashMapCapacity, | |
48 ZoneAllocationPolicy(zone)), | |
49 functions_(base::HashMap::PointersMatch, | |
50 ZoneHashMap::kDefaultHashMapCapacity, | |
51 ZoneAllocationPolicy(zone)), | |
52 global_variables_(base::HashMap::PointersMatch, | |
53 ZoneHashMap::kDefaultHashMapCapacity, | |
54 ZoneAllocationPolicy(zone)), | |
55 scope_(kModuleScope), | |
56 builder_(new (zone) WasmModuleBuilder(zone)), | |
57 current_function_builder_(nullptr), | |
58 literal_(literal), | |
59 isolate_(isolate), | |
60 zone_(zone), | |
61 typer_(typer), | |
62 cache_(TypeCache::Get()), | |
63 breakable_blocks_(zone), | |
64 foreign_variables_(zone), | |
65 init_function_index_(0), | |
66 foreign_init_function_index_(0), | |
67 next_table_index_(0), | |
68 function_tables_(base::HashMap::PointersMatch, | |
69 ZoneHashMap::kDefaultHashMapCapacity, | |
70 ZoneAllocationPolicy(zone)), | |
71 imported_function_table_(this), | |
72 bounds_(typer->bounds()) { | |
73 InitializeAstVisitor(isolate); | |
74 } | |
75 | |
76 void InitializeInitFunction() { | |
77 init_function_index_ = builder_->AddFunction(); | |
78 FunctionSig::Builder b(zone(), 0, 0); | |
79 current_function_builder_ = builder_->FunctionAt(init_function_index_); | |
80 current_function_builder_->SetSignature(b.Build()); | |
81 builder_->MarkStartFunction(init_function_index_); | |
82 current_function_builder_ = nullptr; | |
83 } | |
84 | |
85 void BuildForeignInitFunction() { | |
86 foreign_init_function_index_ = builder_->AddFunction(); | |
87 FunctionSig::Builder b(zone(), 0, foreign_variables_.size()); | |
88 for (auto i = foreign_variables_.begin(); i != foreign_variables_.end(); | |
89 ++i) { | |
90 b.AddParam(i->type); | |
91 } | |
92 current_function_builder_ = | |
93 builder_->FunctionAt(foreign_init_function_index_); | |
94 current_function_builder_->SetExported(); | |
95 std::string raw_name = "__foreign_init__"; | |
96 current_function_builder_->SetName(raw_name.data(), | |
97 static_cast<int>(raw_name.size())); | |
98 current_function_builder_->SetSignature(b.Build()); | |
99 for (size_t pos = 0; pos < foreign_variables_.size(); ++pos) { | |
100 current_function_builder_->EmitGetLocal(static_cast<uint32_t>(pos)); | |
101 ForeignVariable* fv = &foreign_variables_[pos]; | |
102 uint32_t index = LookupOrInsertGlobal(fv->var, fv->type); | |
103 current_function_builder_->EmitWithVarInt(kExprStoreGlobal, index); | |
104 } | |
105 current_function_builder_ = nullptr; | |
106 } | |
107 | |
108 i::Handle<i::FixedArray> GetForeignArgs() { | |
109 i::Handle<FixedArray> ret = isolate_->factory()->NewFixedArray( | |
110 static_cast<int>(foreign_variables_.size())); | |
111 for (size_t i = 0; i < foreign_variables_.size(); ++i) { | |
112 ForeignVariable* fv = &foreign_variables_[i]; | |
113 ret->set(static_cast<int>(i), *fv->name); | |
114 } | |
115 return ret; | |
116 } | |
117 | |
118 void Build() { | |
119 InitializeInitFunction(); | |
120 RECURSE(VisitFunctionLiteral(literal_)); | |
121 BuildForeignInitFunction(); | |
122 } | |
123 | |
124 void VisitVariableDeclaration(VariableDeclaration* decl) override {} | |
125 | |
126 void VisitFunctionDeclaration(FunctionDeclaration* decl) override { | |
127 DCHECK_EQ(kModuleScope, scope_); | |
128 DCHECK_NULL(current_function_builder_); | |
129 uint32_t index = LookupOrInsertFunction(decl->proxy()->var()); | |
130 current_function_builder_ = builder_->FunctionAt(index); | |
131 scope_ = kFuncScope; | |
132 RECURSE(Visit(decl->fun())); | |
133 scope_ = kModuleScope; | |
134 current_function_builder_ = nullptr; | |
135 local_variables_.Clear(); | |
136 } | |
137 | |
138 void VisitImportDeclaration(ImportDeclaration* decl) override {} | |
139 | |
140 void VisitStatements(ZoneList<Statement*>* stmts) override { | |
141 for (int i = 0; i < stmts->length(); ++i) { | |
142 Statement* stmt = stmts->at(i); | |
143 ExpressionStatement* e = stmt->AsExpressionStatement(); | |
144 if (e != nullptr && e->expression()->IsUndefinedLiteral()) { | |
145 continue; | |
146 } | |
147 RECURSE(Visit(stmt)); | |
148 if (stmt->IsJump()) break; | |
149 } | |
150 } | |
151 | |
152 void VisitBlock(Block* stmt) override { | |
153 if (stmt->statements()->length() == 1) { | |
154 ExpressionStatement* expr = | |
155 stmt->statements()->at(0)->AsExpressionStatement(); | |
156 if (expr != nullptr) { | |
157 if (expr->expression()->IsAssignment()) { | |
158 RECURSE(VisitExpressionStatement(expr)); | |
159 return; | |
160 } | |
161 } | |
162 } | |
163 if (scope_ == kFuncScope) { | |
164 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock, | |
165 false); | |
166 RECURSE(VisitStatements(stmt->statements())); | |
167 } else { | |
168 RECURSE(VisitStatements(stmt->statements())); | |
169 } | |
170 } | |
171 | |
172 class BlockVisitor { | |
173 private: | |
174 AsmWasmBuilderImpl* builder_; | |
175 | |
176 public: | |
177 BlockVisitor(AsmWasmBuilderImpl* builder, BreakableStatement* stmt, | |
178 WasmOpcode opcode, bool is_loop) | |
179 : builder_(builder) { | |
180 builder_->breakable_blocks_.push_back(std::make_pair(stmt, is_loop)); | |
181 builder_->current_function_builder_->Emit(opcode); | |
182 } | |
183 ~BlockVisitor() { | |
184 builder_->current_function_builder_->Emit(kExprEnd); | |
185 builder_->breakable_blocks_.pop_back(); | |
186 } | |
187 }; | |
188 | |
189 void VisitExpressionStatement(ExpressionStatement* stmt) override { | |
190 RECURSE(Visit(stmt->expression())); | |
191 } | |
192 | |
193 void VisitEmptyStatement(EmptyStatement* stmt) override {} | |
194 | |
195 void VisitEmptyParentheses(EmptyParentheses* paren) override { | |
196 UNREACHABLE(); | |
197 } | |
198 | |
199 void VisitIfStatement(IfStatement* stmt) override { | |
200 DCHECK_EQ(kFuncScope, scope_); | |
201 RECURSE(Visit(stmt->condition())); | |
202 current_function_builder_->Emit(kExprIf); | |
203 // WASM ifs come with implement blocks for both arms. | |
204 breakable_blocks_.push_back(std::make_pair(nullptr, false)); | |
205 if (stmt->HasThenStatement()) { | |
206 RECURSE(Visit(stmt->then_statement())); | |
207 } | |
208 if (stmt->HasElseStatement()) { | |
209 current_function_builder_->Emit(kExprElse); | |
210 RECURSE(Visit(stmt->else_statement())); | |
211 } | |
212 current_function_builder_->Emit(kExprEnd); | |
213 breakable_blocks_.pop_back(); | |
214 } | |
215 | |
216 void VisitContinueStatement(ContinueStatement* stmt) override { | |
217 DCHECK_EQ(kFuncScope, scope_); | |
218 DCHECK_NOT_NULL(stmt->target()); | |
219 int i = static_cast<int>(breakable_blocks_.size()) - 1; | |
220 int block_distance = 0; | |
221 for (; i >= 0; i--) { | |
222 auto elem = breakable_blocks_.at(i); | |
223 if (elem.first == stmt->target()) { | |
224 DCHECK(elem.second); | |
225 break; | |
226 } else if (elem.second) { | |
227 block_distance += 2; | |
228 } else { | |
229 block_distance += 1; | |
230 } | |
231 } | |
232 DCHECK(i >= 0); | |
233 current_function_builder_->EmitWithU8(kExprBr, ARITY_0); | |
234 current_function_builder_->EmitVarInt(block_distance); | |
235 } | |
236 | |
237 void VisitBreakStatement(BreakStatement* stmt) override { | |
238 DCHECK_EQ(kFuncScope, scope_); | |
239 DCHECK_NOT_NULL(stmt->target()); | |
240 int i = static_cast<int>(breakable_blocks_.size()) - 1; | |
241 int block_distance = 0; | |
242 for (; i >= 0; i--) { | |
243 auto elem = breakable_blocks_.at(i); | |
244 if (elem.first == stmt->target()) { | |
245 if (elem.second) { | |
246 block_distance++; | |
247 } | |
248 break; | |
249 } else if (elem.second) { | |
250 block_distance += 2; | |
251 } else { | |
252 block_distance += 1; | |
253 } | |
254 } | |
255 DCHECK(i >= 0); | |
256 current_function_builder_->EmitWithU8(kExprBr, ARITY_0); | |
257 current_function_builder_->EmitVarInt(block_distance); | |
258 } | |
259 | |
260 void VisitReturnStatement(ReturnStatement* stmt) override { | |
261 if (scope_ == kModuleScope) { | |
262 scope_ = kExportScope; | |
263 RECURSE(Visit(stmt->expression())); | |
264 scope_ = kModuleScope; | |
265 } else if (scope_ == kFuncScope) { | |
266 RECURSE(Visit(stmt->expression())); | |
267 uint8_t arity = | |
268 TypeOf(stmt->expression()) == kAstStmt ? ARITY_0 : ARITY_1; | |
269 current_function_builder_->EmitWithU8(kExprReturn, arity); | |
270 } else { | |
271 UNREACHABLE(); | |
272 } | |
273 } | |
274 | |
275 void VisitWithStatement(WithStatement* stmt) override { UNREACHABLE(); } | |
276 | |
277 void HandleCase(CaseNode* node, | |
278 const ZoneMap<int, unsigned int>& case_to_block, | |
279 VariableProxy* tag, int default_block, int if_depth) { | |
280 int prev_if_depth = if_depth; | |
281 if (node->left != nullptr) { | |
282 VisitVariableProxy(tag); | |
283 current_function_builder_->EmitI32Const(node->begin); | |
284 current_function_builder_->Emit(kExprI32LtS); | |
285 current_function_builder_->Emit(kExprIf); | |
286 if_depth++; | |
287 breakable_blocks_.push_back(std::make_pair(nullptr, false)); | |
288 HandleCase(node->left, case_to_block, tag, default_block, if_depth); | |
289 current_function_builder_->Emit(kExprElse); | |
290 } | |
291 if (node->right != nullptr) { | |
292 VisitVariableProxy(tag); | |
293 current_function_builder_->EmitI32Const(node->end); | |
294 current_function_builder_->Emit(kExprI32GtS); | |
295 current_function_builder_->Emit(kExprIf); | |
296 if_depth++; | |
297 breakable_blocks_.push_back(std::make_pair(nullptr, false)); | |
298 HandleCase(node->right, case_to_block, tag, default_block, if_depth); | |
299 current_function_builder_->Emit(kExprElse); | |
300 } | |
301 if (node->begin == node->end) { | |
302 VisitVariableProxy(tag); | |
303 current_function_builder_->EmitI32Const(node->begin); | |
304 current_function_builder_->Emit(kExprI32Eq); | |
305 current_function_builder_->Emit(kExprIf); | |
306 DCHECK(case_to_block.find(node->begin) != case_to_block.end()); | |
307 current_function_builder_->EmitWithU8(kExprBr, ARITY_0); | |
308 current_function_builder_->EmitVarInt(1 + if_depth + | |
309 case_to_block.at(node->begin)); | |
310 current_function_builder_->Emit(kExprEnd); | |
311 } else { | |
312 if (node->begin != 0) { | |
313 VisitVariableProxy(tag); | |
314 current_function_builder_->EmitI32Const(node->begin); | |
315 current_function_builder_->Emit(kExprI32Sub); | |
316 } else { | |
317 VisitVariableProxy(tag); | |
318 } | |
319 current_function_builder_->EmitWithU8(kExprBrTable, ARITY_0); | |
320 current_function_builder_->EmitVarInt(node->end - node->begin + 1); | |
321 for (int v = node->begin; v <= node->end; v++) { | |
322 if (case_to_block.find(v) != case_to_block.end()) { | |
323 byte break_code[] = {BR_TARGET(if_depth + case_to_block.at(v))}; | |
324 current_function_builder_->EmitCode(break_code, sizeof(break_code)); | |
325 } else { | |
326 byte break_code[] = {BR_TARGET(if_depth + default_block)}; | |
327 current_function_builder_->EmitCode(break_code, sizeof(break_code)); | |
328 } | |
329 if (v == kMaxInt) { | |
330 break; | |
331 } | |
332 } | |
333 byte break_code[] = {BR_TARGET(if_depth + default_block)}; | |
334 current_function_builder_->EmitCode(break_code, sizeof(break_code)); | |
335 } | |
336 | |
337 while (if_depth-- != prev_if_depth) { | |
338 breakable_blocks_.pop_back(); | |
339 current_function_builder_->Emit(kExprEnd); | |
340 } | |
341 } | |
342 | |
343 void VisitSwitchStatement(SwitchStatement* stmt) override { | |
344 VariableProxy* tag = stmt->tag()->AsVariableProxy(); | |
345 DCHECK_NOT_NULL(tag); | |
346 ZoneList<CaseClause*>* clauses = stmt->cases(); | |
347 int case_count = clauses->length(); | |
348 if (case_count == 0) { | |
349 return; | |
350 } | |
351 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock, false); | |
352 ZoneVector<BlockVisitor*> blocks(zone_); | |
353 ZoneVector<int32_t> cases(zone_); | |
354 ZoneMap<int, unsigned int> case_to_block(zone_); | |
355 bool has_default = false; | |
356 for (int i = case_count - 1; i >= 0; i--) { | |
357 CaseClause* clause = clauses->at(i); | |
358 blocks.push_back(new BlockVisitor(this, nullptr, kExprBlock, false)); | |
359 if (!clause->is_default()) { | |
360 Literal* label = clause->label()->AsLiteral(); | |
361 Handle<Object> value = label->value(); | |
362 DCHECK(value->IsNumber() && | |
363 bounds_->get(label).upper->Is(cache_.kAsmSigned)); | |
364 int32_t label_value; | |
365 if (!value->ToInt32(&label_value)) { | |
366 UNREACHABLE(); | |
367 } | |
368 case_to_block[label_value] = i; | |
369 cases.push_back(label_value); | |
370 } else { | |
371 DCHECK_EQ(i, case_count - 1); | |
372 has_default = true; | |
373 } | |
374 } | |
375 if (!has_default || case_count > 1) { | |
376 int default_block = has_default ? case_count - 1 : case_count; | |
377 BlockVisitor switch_logic_block(this, nullptr, kExprBlock, false); | |
378 CaseNode* root = OrderCases(&cases, zone_); | |
379 HandleCase(root, case_to_block, tag, default_block, 0); | |
380 if (root->left != nullptr || root->right != nullptr || | |
381 root->begin == root->end) { | |
382 current_function_builder_->EmitWithU8(kExprBr, ARITY_0); | |
383 current_function_builder_->EmitVarInt(default_block); | |
384 } | |
385 } | |
386 for (int i = 0; i < case_count; ++i) { | |
387 CaseClause* clause = clauses->at(i); | |
388 RECURSE(VisitStatements(clause->statements())); | |
389 BlockVisitor* v = blocks.at(case_count - i - 1); | |
390 blocks.pop_back(); | |
391 delete v; | |
392 } | |
393 } | |
394 | |
395 void VisitCaseClause(CaseClause* clause) override { UNREACHABLE(); } | |
396 | |
397 void VisitDoWhileStatement(DoWhileStatement* stmt) override { | |
398 DCHECK_EQ(kFuncScope, scope_); | |
399 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true); | |
400 RECURSE(Visit(stmt->body())); | |
401 RECURSE(Visit(stmt->cond())); | |
402 current_function_builder_->Emit(kExprIf); | |
403 current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 1); | |
404 current_function_builder_->Emit(kExprEnd); | |
405 } | |
406 | |
407 void VisitWhileStatement(WhileStatement* stmt) override { | |
408 DCHECK_EQ(kFuncScope, scope_); | |
409 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true); | |
410 RECURSE(Visit(stmt->cond())); | |
411 breakable_blocks_.push_back(std::make_pair(nullptr, false)); | |
412 current_function_builder_->Emit(kExprIf); | |
413 RECURSE(Visit(stmt->body())); | |
414 current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 1); | |
415 current_function_builder_->Emit(kExprEnd); | |
416 breakable_blocks_.pop_back(); | |
417 } | |
418 | |
419 void VisitForStatement(ForStatement* stmt) override { | |
420 DCHECK_EQ(kFuncScope, scope_); | |
421 if (stmt->init() != nullptr) { | |
422 RECURSE(Visit(stmt->init())); | |
423 } | |
424 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true); | |
425 if (stmt->cond() != nullptr) { | |
426 RECURSE(Visit(stmt->cond())); | |
427 current_function_builder_->Emit(kExprI32Eqz); | |
428 current_function_builder_->Emit(kExprIf); | |
429 current_function_builder_->Emit(kExprNop); | |
430 current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 2); | |
431 current_function_builder_->Emit(kExprEnd); | |
432 } | |
433 if (stmt->body() != nullptr) { | |
434 RECURSE(Visit(stmt->body())); | |
435 } | |
436 if (stmt->next() != nullptr) { | |
437 RECURSE(Visit(stmt->next())); | |
438 } | |
439 current_function_builder_->Emit(kExprNop); | |
440 current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 0); | |
441 } | |
442 | |
443 void VisitForInStatement(ForInStatement* stmt) override { UNREACHABLE(); } | |
444 | |
445 void VisitForOfStatement(ForOfStatement* stmt) override { UNREACHABLE(); } | |
446 | |
447 void VisitTryCatchStatement(TryCatchStatement* stmt) override { | |
448 UNREACHABLE(); | |
449 } | |
450 | |
451 void VisitTryFinallyStatement(TryFinallyStatement* stmt) override { | |
452 UNREACHABLE(); | |
453 } | |
454 | |
455 void VisitDebuggerStatement(DebuggerStatement* stmt) override { | |
456 UNREACHABLE(); | |
457 } | |
458 | |
459 void VisitFunctionLiteral(FunctionLiteral* expr) override { | |
460 Scope* scope = expr->scope(); | |
461 if (scope_ == kFuncScope) { | |
462 if (bounds_->get(expr).lower->IsFunction()) { | |
463 // Build the signature for the function. | |
464 FunctionType* func_type = bounds_->get(expr).lower->AsFunction(); | |
465 LocalType return_type = TypeFrom(func_type->Result()); | |
466 FunctionSig::Builder b(zone(), return_type == kAstStmt ? 0 : 1, | |
467 func_type->Arity()); | |
468 if (return_type != kAstStmt) b.AddReturn(return_type); | |
469 for (int i = 0; i < expr->parameter_count(); ++i) { | |
470 LocalType type = TypeFrom(func_type->Parameter(i)); | |
471 DCHECK_NE(kAstStmt, type); | |
472 b.AddParam(type); | |
473 InsertParameter(scope->parameter(i), type, i); | |
474 } | |
475 current_function_builder_->SetSignature(b.Build()); | |
476 } else { | |
477 UNREACHABLE(); | |
478 } | |
479 } | |
480 RECURSE(VisitStatements(expr->body())); | |
481 RECURSE(VisitDeclarations(scope->declarations())); | |
482 } | |
483 | |
484 void VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) override { | |
485 UNREACHABLE(); | |
486 } | |
487 | |
488 void VisitConditional(Conditional* expr) override { | |
489 DCHECK_EQ(kFuncScope, scope_); | |
490 RECURSE(Visit(expr->condition())); | |
491 // WASM ifs come with implicit blocks for both arms. | |
492 breakable_blocks_.push_back(std::make_pair(nullptr, false)); | |
493 current_function_builder_->Emit(kExprIf); | |
494 RECURSE(Visit(expr->then_expression())); | |
495 current_function_builder_->Emit(kExprElse); | |
496 RECURSE(Visit(expr->else_expression())); | |
497 current_function_builder_->Emit(kExprEnd); | |
498 breakable_blocks_.pop_back(); | |
499 } | |
500 | |
501 bool VisitStdlibConstant(Variable* var) { | |
502 AsmTyper::StandardMember standard_object = | |
503 typer_->VariableAsStandardMember(var); | |
504 double value; | |
505 switch (standard_object) { | |
506 case AsmTyper::kInfinity: { | |
507 value = std::numeric_limits<double>::infinity(); | |
508 break; | |
509 } | |
510 case AsmTyper::kNaN: { | |
511 value = std::numeric_limits<double>::quiet_NaN(); | |
512 break; | |
513 } | |
514 case AsmTyper::kMathE: { | |
515 value = M_E; | |
516 break; | |
517 } | |
518 case AsmTyper::kMathLN10: { | |
519 value = M_LN10; | |
520 break; | |
521 } | |
522 case AsmTyper::kMathLN2: { | |
523 value = M_LN2; | |
524 break; | |
525 } | |
526 case AsmTyper::kMathLOG10E: { | |
527 value = M_LOG10E; | |
528 break; | |
529 } | |
530 case AsmTyper::kMathLOG2E: { | |
531 value = M_LOG2E; | |
532 break; | |
533 } | |
534 case AsmTyper::kMathPI: { | |
535 value = M_PI; | |
536 break; | |
537 } | |
538 case AsmTyper::kMathSQRT1_2: { | |
539 value = M_SQRT1_2; | |
540 break; | |
541 } | |
542 case AsmTyper::kMathSQRT2: { | |
543 value = M_SQRT2; | |
544 break; | |
545 } | |
546 default: { return false; } | |
547 } | |
548 byte code[] = {WASM_F64(value)}; | |
549 current_function_builder_->EmitCode(code, sizeof(code)); | |
550 return true; | |
551 } | |
552 | |
553 void VisitVariableProxy(VariableProxy* expr) override { | |
554 if (scope_ == kFuncScope || scope_ == kInitScope) { | |
555 Variable* var = expr->var(); | |
556 if (VisitStdlibConstant(var)) { | |
557 return; | |
558 } | |
559 LocalType var_type = TypeOf(expr); | |
560 DCHECK_NE(kAstStmt, var_type); | |
561 if (var->IsContextSlot()) { | |
562 current_function_builder_->EmitWithVarInt( | |
563 kExprLoadGlobal, LookupOrInsertGlobal(var, var_type)); | |
564 } else { | |
565 current_function_builder_->EmitGetLocal( | |
566 LookupOrInsertLocal(var, var_type)); | |
567 } | |
568 } | |
569 } | |
570 | |
571 void VisitLiteral(Literal* expr) override { | |
572 Handle<Object> value = expr->value(); | |
573 if (!value->IsNumber() || (scope_ != kFuncScope && scope_ != kInitScope)) { | |
574 return; | |
575 } | |
576 Type* type = bounds_->get(expr).upper; | |
577 if (type->Is(cache_.kAsmSigned)) { | |
578 int32_t i = 0; | |
579 if (!value->ToInt32(&i)) { | |
580 UNREACHABLE(); | |
581 } | |
582 byte code[] = {WASM_I32V(i)}; | |
583 current_function_builder_->EmitCode(code, sizeof(code)); | |
584 } else if (type->Is(cache_.kAsmUnsigned) || type->Is(cache_.kAsmFixnum)) { | |
585 uint32_t u = 0; | |
586 if (!value->ToUint32(&u)) { | |
587 UNREACHABLE(); | |
588 } | |
589 int32_t i = static_cast<int32_t>(u); | |
590 byte code[] = {WASM_I32V(i)}; | |
591 current_function_builder_->EmitCode(code, sizeof(code)); | |
592 } else if (type->Is(cache_.kAsmDouble)) { | |
593 double val = expr->raw_value()->AsNumber(); | |
594 byte code[] = {WASM_F64(val)}; | |
595 current_function_builder_->EmitCode(code, sizeof(code)); | |
596 } else { | |
597 UNREACHABLE(); | |
598 } | |
599 } | |
600 | |
601 void VisitRegExpLiteral(RegExpLiteral* expr) override { UNREACHABLE(); } | |
602 | |
603 void VisitObjectLiteral(ObjectLiteral* expr) override { | |
604 ZoneList<ObjectLiteralProperty*>* props = expr->properties(); | |
605 for (int i = 0; i < props->length(); ++i) { | |
606 ObjectLiteralProperty* prop = props->at(i); | |
607 DCHECK_EQ(kExportScope, scope_); | |
608 VariableProxy* expr = prop->value()->AsVariableProxy(); | |
609 DCHECK_NOT_NULL(expr); | |
610 Variable* var = expr->var(); | |
611 Literal* name = prop->key()->AsLiteral(); | |
612 DCHECK_NOT_NULL(name); | |
613 DCHECK(name->IsPropertyName()); | |
614 const AstRawString* raw_name = name->AsRawPropertyName(); | |
615 if (var->is_function()) { | |
616 uint32_t index = LookupOrInsertFunction(var); | |
617 builder_->FunctionAt(index)->SetExported(); | |
618 builder_->FunctionAt(index)->SetName( | |
619 reinterpret_cast<const char*>(raw_name->raw_data()), | |
620 raw_name->length()); | |
621 } | |
622 } | |
623 } | |
624 | |
625 void VisitArrayLiteral(ArrayLiteral* expr) override { UNREACHABLE(); } | |
626 | |
627 void LoadInitFunction() { | |
628 current_function_builder_ = builder_->FunctionAt(init_function_index_); | |
629 scope_ = kInitScope; | |
630 } | |
631 | |
632 void UnLoadInitFunction() { | |
633 scope_ = kModuleScope; | |
634 current_function_builder_ = nullptr; | |
635 } | |
636 | |
637 void AddFunctionTable(VariableProxy* table, ArrayLiteral* funcs) { | |
638 FunctionType* func_type = | |
639 bounds_->get(funcs).lower->AsArray()->Element()->AsFunction(); | |
640 LocalType return_type = TypeFrom(func_type->Result()); | |
641 FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1, | |
642 func_type->Arity()); | |
643 if (return_type != kAstStmt) { | |
644 sig.AddReturn(static_cast<LocalType>(return_type)); | |
645 } | |
646 for (int i = 0; i < func_type->Arity(); ++i) { | |
647 sig.AddParam(TypeFrom(func_type->Parameter(i))); | |
648 } | |
649 uint32_t signature_index = builder_->AddSignature(sig.Build()); | |
650 InsertFunctionTable(table->var(), next_table_index_, signature_index); | |
651 next_table_index_ += funcs->values()->length(); | |
652 for (int i = 0; i < funcs->values()->length(); ++i) { | |
653 VariableProxy* func = funcs->values()->at(i)->AsVariableProxy(); | |
654 DCHECK_NOT_NULL(func); | |
655 builder_->AddIndirectFunction(LookupOrInsertFunction(func->var())); | |
656 } | |
657 } | |
658 | |
659 struct FunctionTableIndices : public ZoneObject { | |
660 uint32_t start_index; | |
661 uint32_t signature_index; | |
662 }; | |
663 | |
664 void InsertFunctionTable(Variable* v, uint32_t start_index, | |
665 uint32_t signature_index) { | |
666 FunctionTableIndices* container = new (zone()) FunctionTableIndices(); | |
667 container->start_index = start_index; | |
668 container->signature_index = signature_index; | |
669 ZoneHashMap::Entry* entry = function_tables_.LookupOrInsert( | |
670 v, ComputePointerHash(v), ZoneAllocationPolicy(zone())); | |
671 entry->value = container; | |
672 } | |
673 | |
674 FunctionTableIndices* LookupFunctionTable(Variable* v) { | |
675 ZoneHashMap::Entry* entry = | |
676 function_tables_.Lookup(v, ComputePointerHash(v)); | |
677 DCHECK_NOT_NULL(entry); | |
678 return reinterpret_cast<FunctionTableIndices*>(entry->value); | |
679 } | |
680 | |
681 class ImportedFunctionTable { | |
682 private: | |
683 class ImportedFunctionIndices : public ZoneObject { | |
684 public: | |
685 const char* name_; | |
686 int name_length_; | |
687 WasmModuleBuilder::SignatureMap signature_to_index_; | |
688 | |
689 ImportedFunctionIndices(const char* name, int name_length, Zone* zone) | |
690 : name_(name), name_length_(name_length), signature_to_index_(zone) {} | |
691 }; | |
692 ZoneHashMap table_; | |
693 AsmWasmBuilderImpl* builder_; | |
694 | |
695 public: | |
696 explicit ImportedFunctionTable(AsmWasmBuilderImpl* builder) | |
697 : table_(base::HashMap::PointersMatch, | |
698 ZoneHashMap::kDefaultHashMapCapacity, | |
699 ZoneAllocationPolicy(builder->zone())), | |
700 builder_(builder) {} | |
701 | |
702 void AddImport(Variable* v, const char* name, int name_length) { | |
703 ImportedFunctionIndices* indices = new (builder_->zone()) | |
704 ImportedFunctionIndices(name, name_length, builder_->zone()); | |
705 ZoneHashMap::Entry* entry = table_.LookupOrInsert( | |
706 v, ComputePointerHash(v), ZoneAllocationPolicy(builder_->zone())); | |
707 entry->value = indices; | |
708 } | |
709 | |
710 uint32_t GetFunctionIndex(Variable* v, FunctionSig* sig) { | |
711 ZoneHashMap::Entry* entry = table_.Lookup(v, ComputePointerHash(v)); | |
712 DCHECK_NOT_NULL(entry); | |
713 ImportedFunctionIndices* indices = | |
714 reinterpret_cast<ImportedFunctionIndices*>(entry->value); | |
715 WasmModuleBuilder::SignatureMap::iterator pos = | |
716 indices->signature_to_index_.find(sig); | |
717 if (pos != indices->signature_to_index_.end()) { | |
718 return pos->second; | |
719 } else { | |
720 uint32_t index = builder_->builder_->AddImport( | |
721 indices->name_, indices->name_length_, sig); | |
722 indices->signature_to_index_[sig] = index; | |
723 return index; | |
724 } | |
725 } | |
726 }; | |
727 | |
728 void EmitAssignmentLhs(Expression* target, MachineType* mtype) { | |
729 // Match the left hand side of the assignment. | |
730 VariableProxy* target_var = target->AsVariableProxy(); | |
731 if (target_var != nullptr) { | |
732 // Left hand side is a local or a global variable, no code on LHS. | |
733 return; | |
734 } | |
735 | |
736 Property* target_prop = target->AsProperty(); | |
737 if (target_prop != nullptr) { | |
738 // Left hand side is a property access, i.e. the asm.js heap. | |
739 VisitPropertyAndEmitIndex(target_prop, mtype); | |
740 return; | |
741 } | |
742 | |
743 if (target_var == nullptr && target_prop == nullptr) { | |
744 UNREACHABLE(); // invalid assignment. | |
745 } | |
746 } | |
747 | |
748 void EmitAssignmentRhs(Expression* target, Expression* value, bool* is_nop) { | |
749 BinaryOperation* binop = value->AsBinaryOperation(); | |
750 if (binop != nullptr) { | |
751 if (scope_ == kInitScope) { | |
752 // Handle foreign variables in the initialization scope. | |
753 Property* prop = binop->left()->AsProperty(); | |
754 if (binop->op() == Token::MUL) { | |
755 DCHECK(binop->right()->IsLiteral()); | |
756 DCHECK_EQ(1.0, binop->right()->AsLiteral()->raw_value()->AsNumber()); | |
757 DCHECK(binop->right()->AsLiteral()->raw_value()->ContainsDot()); | |
758 DCHECK(target->IsVariableProxy()); | |
759 VisitForeignVariable(true, target->AsVariableProxy()->var(), prop); | |
760 *is_nop = true; | |
761 return; | |
762 } else if (binop->op() == Token::BIT_OR) { | |
763 DCHECK(binop->right()->IsLiteral()); | |
764 DCHECK_EQ(0.0, binop->right()->AsLiteral()->raw_value()->AsNumber()); | |
765 DCHECK(!binop->right()->AsLiteral()->raw_value()->ContainsDot()); | |
766 DCHECK(target->IsVariableProxy()); | |
767 VisitForeignVariable(false, target->AsVariableProxy()->var(), prop); | |
768 *is_nop = true; | |
769 return; | |
770 } else { | |
771 UNREACHABLE(); | |
772 } | |
773 } | |
774 if (MatchBinaryOperation(binop) == kAsIs) { | |
775 VariableProxy* target_var = target->AsVariableProxy(); | |
776 VariableProxy* effective_value_var = GetLeft(binop)->AsVariableProxy(); | |
777 if (target_var != nullptr && effective_value_var != nullptr && | |
778 target_var->var() == effective_value_var->var()) { | |
779 *is_nop = true; | |
780 return; | |
781 } | |
782 } | |
783 } | |
784 RECURSE(Visit(value)); | |
785 } | |
786 | |
787 void EmitAssignment(Assignment* expr, MachineType type) { | |
788 // Match the left hand side of the assignment. | |
789 VariableProxy* target_var = expr->target()->AsVariableProxy(); | |
790 if (target_var != nullptr) { | |
791 // Left hand side is a local or a global variable. | |
792 Variable* var = target_var->var(); | |
793 LocalType var_type = TypeOf(expr); | |
794 DCHECK_NE(kAstStmt, var_type); | |
795 if (var->IsContextSlot()) { | |
796 current_function_builder_->EmitWithVarInt( | |
797 kExprStoreGlobal, LookupOrInsertGlobal(var, var_type)); | |
798 } else { | |
799 current_function_builder_->EmitSetLocal( | |
800 LookupOrInsertLocal(var, var_type)); | |
801 } | |
802 } | |
803 | |
804 Property* target_prop = expr->target()->AsProperty(); | |
805 if (target_prop != nullptr) { | |
806 // Left hand side is a property access, i.e. the asm.js heap. | |
807 if (TypeOf(expr->value()) == kAstF64 && expr->target()->IsProperty() && | |
808 bounds_->get(expr->target()->AsProperty()->obj()) | |
809 .lower->Is(cache_.kFloat32Array)) { | |
810 current_function_builder_->Emit(kExprF32ConvertF64); | |
811 } | |
812 WasmOpcode opcode; | |
813 if (type == MachineType::Int8()) { | |
814 opcode = kExprI32AsmjsStoreMem8; | |
815 } else if (type == MachineType::Uint8()) { | |
816 opcode = kExprI32AsmjsStoreMem8; | |
817 } else if (type == MachineType::Int16()) { | |
818 opcode = kExprI32AsmjsStoreMem16; | |
819 } else if (type == MachineType::Uint16()) { | |
820 opcode = kExprI32AsmjsStoreMem16; | |
821 } else if (type == MachineType::Int32()) { | |
822 opcode = kExprI32AsmjsStoreMem; | |
823 } else if (type == MachineType::Uint32()) { | |
824 opcode = kExprI32AsmjsStoreMem; | |
825 } else if (type == MachineType::Float32()) { | |
826 opcode = kExprF32AsmjsStoreMem; | |
827 } else if (type == MachineType::Float64()) { | |
828 opcode = kExprF64AsmjsStoreMem; | |
829 } else { | |
830 UNREACHABLE(); | |
831 } | |
832 current_function_builder_->Emit(opcode); | |
833 } | |
834 | |
835 if (target_var == nullptr && target_prop == nullptr) { | |
836 UNREACHABLE(); // invalid assignment. | |
837 } | |
838 } | |
839 | |
840 void VisitAssignment(Assignment* expr) override { | |
841 bool as_init = false; | |
842 if (scope_ == kModuleScope) { | |
843 Property* prop = expr->value()->AsProperty(); | |
844 if (prop != nullptr) { | |
845 VariableProxy* vp = prop->obj()->AsVariableProxy(); | |
846 if (vp != nullptr && vp->var()->IsParameter() && | |
847 vp->var()->index() == 1) { | |
848 VariableProxy* target = expr->target()->AsVariableProxy(); | |
849 if (bounds_->get(target).lower->Is(Type::Function())) { | |
850 const AstRawString* name = | |
851 prop->key()->AsLiteral()->AsRawPropertyName(); | |
852 imported_function_table_.AddImport( | |
853 target->var(), reinterpret_cast<const char*>(name->raw_data()), | |
854 name->length()); | |
855 } | |
856 } | |
857 // Property values in module scope don't emit code, so return. | |
858 return; | |
859 } | |
860 ArrayLiteral* funcs = expr->value()->AsArrayLiteral(); | |
861 if (funcs != nullptr && | |
862 bounds_->get(funcs).lower->AsArray()->Element()->IsFunction()) { | |
863 VariableProxy* target = expr->target()->AsVariableProxy(); | |
864 DCHECK_NOT_NULL(target); | |
865 AddFunctionTable(target, funcs); | |
866 // Only add to the function table. No init needed. | |
867 return; | |
868 } | |
869 if (expr->value()->IsCallNew()) { | |
870 // No init code to emit for CallNew nodes. | |
871 return; | |
872 } | |
873 as_init = true; | |
874 } | |
875 | |
876 if (as_init) LoadInitFunction(); | |
877 MachineType mtype; | |
878 bool is_nop = false; | |
879 EmitAssignmentLhs(expr->target(), &mtype); | |
880 EmitAssignmentRhs(expr->target(), expr->value(), &is_nop); | |
881 if (!is_nop) { | |
882 EmitAssignment(expr, mtype); | |
883 } | |
884 if (as_init) UnLoadInitFunction(); | |
885 } | |
886 | |
887 void VisitYield(Yield* expr) override { UNREACHABLE(); } | |
888 | |
889 void VisitThrow(Throw* expr) override { UNREACHABLE(); } | |
890 | |
891 void VisitForeignVariable(bool is_float, Variable* var, Property* expr) { | |
892 DCHECK(expr->obj()->AsVariableProxy()); | |
893 DCHECK(VariableLocation::PARAMETER == | |
894 expr->obj()->AsVariableProxy()->var()->location()); | |
895 DCHECK_EQ(1, expr->obj()->AsVariableProxy()->var()->index()); | |
896 Literal* key_literal = expr->key()->AsLiteral(); | |
897 DCHECK_NOT_NULL(key_literal); | |
898 if (!key_literal->value().is_null()) { | |
899 Handle<Name> name = | |
900 i::Object::ToName(isolate_, key_literal->value()).ToHandleChecked(); | |
901 LocalType type = is_float ? kAstF64 : kAstI32; | |
902 foreign_variables_.push_back({name, var, type}); | |
903 } | |
904 } | |
905 | |
906 void VisitPropertyAndEmitIndex(Property* expr, MachineType* mtype) { | |
907 Expression* obj = expr->obj(); | |
908 DCHECK_EQ(bounds_->get(obj).lower, bounds_->get(obj).upper); | |
909 Type* type = bounds_->get(obj).lower; | |
910 int size; | |
911 if (type->Is(cache_.kUint8Array)) { | |
912 *mtype = MachineType::Uint8(); | |
913 size = 1; | |
914 } else if (type->Is(cache_.kInt8Array)) { | |
915 *mtype = MachineType::Int8(); | |
916 size = 1; | |
917 } else if (type->Is(cache_.kUint16Array)) { | |
918 *mtype = MachineType::Uint16(); | |
919 size = 2; | |
920 } else if (type->Is(cache_.kInt16Array)) { | |
921 *mtype = MachineType::Int16(); | |
922 size = 2; | |
923 } else if (type->Is(cache_.kUint32Array)) { | |
924 *mtype = MachineType::Uint32(); | |
925 size = 4; | |
926 } else if (type->Is(cache_.kInt32Array)) { | |
927 *mtype = MachineType::Int32(); | |
928 size = 4; | |
929 } else if (type->Is(cache_.kUint32Array)) { | |
930 *mtype = MachineType::Uint32(); | |
931 size = 4; | |
932 } else if (type->Is(cache_.kFloat32Array)) { | |
933 *mtype = MachineType::Float32(); | |
934 size = 4; | |
935 } else if (type->Is(cache_.kFloat64Array)) { | |
936 *mtype = MachineType::Float64(); | |
937 size = 8; | |
938 } else { | |
939 UNREACHABLE(); | |
940 } | |
941 if (size == 1) { | |
942 // Allow more general expression in byte arrays than the spec | |
943 // strictly permits. | |
944 // Early versions of Emscripten emit HEAP8[HEAP32[..]|0] in | |
945 // places that strictly should be HEAP8[HEAP32[..]>>0]. | |
946 RECURSE(Visit(expr->key())); | |
947 return; | |
948 } | |
949 | |
950 Literal* value = expr->key()->AsLiteral(); | |
951 if (value) { | |
952 DCHECK(value->raw_value()->IsNumber()); | |
953 DCHECK_EQ(kAstI32, TypeOf(value)); | |
954 int32_t val = static_cast<int32_t>(value->raw_value()->AsNumber()); | |
955 // TODO(titzer): handle overflow here. | |
956 current_function_builder_->EmitI32Const(val * size); | |
957 return; | |
958 } | |
959 BinaryOperation* binop = expr->key()->AsBinaryOperation(); | |
960 if (binop) { | |
961 DCHECK_EQ(Token::SAR, binop->op()); | |
962 DCHECK(binop->right()->AsLiteral()->raw_value()->IsNumber()); | |
963 DCHECK(kAstI32 == TypeOf(binop->right()->AsLiteral())); | |
964 DCHECK_EQ(size, | |
965 1 << static_cast<int>( | |
966 binop->right()->AsLiteral()->raw_value()->AsNumber())); | |
967 // Mask bottom bits to match asm.js behavior. | |
968 byte mask = static_cast<byte>(~(size - 1)); | |
969 RECURSE(Visit(binop->left())); | |
970 current_function_builder_->EmitWithU8(kExprI8Const, mask); | |
971 current_function_builder_->Emit(kExprI32And); | |
972 return; | |
973 } | |
974 UNREACHABLE(); | |
975 } | |
976 | |
977 void VisitProperty(Property* expr) override { | |
978 MachineType type; | |
979 VisitPropertyAndEmitIndex(expr, &type); | |
980 WasmOpcode opcode; | |
981 if (type == MachineType::Int8()) { | |
982 opcode = kExprI32AsmjsLoadMem8S; | |
983 } else if (type == MachineType::Uint8()) { | |
984 opcode = kExprI32AsmjsLoadMem8U; | |
985 } else if (type == MachineType::Int16()) { | |
986 opcode = kExprI32AsmjsLoadMem16S; | |
987 } else if (type == MachineType::Uint16()) { | |
988 opcode = kExprI32AsmjsLoadMem16U; | |
989 } else if (type == MachineType::Int32()) { | |
990 opcode = kExprI32AsmjsLoadMem; | |
991 } else if (type == MachineType::Uint32()) { | |
992 opcode = kExprI32AsmjsLoadMem; | |
993 } else if (type == MachineType::Float32()) { | |
994 opcode = kExprF32AsmjsLoadMem; | |
995 } else if (type == MachineType::Float64()) { | |
996 opcode = kExprF64AsmjsLoadMem; | |
997 } else { | |
998 UNREACHABLE(); | |
999 } | |
1000 | |
1001 current_function_builder_->Emit(opcode); | |
1002 } | |
1003 | |
1004 bool VisitStdlibFunction(Call* call, VariableProxy* expr) { | |
1005 Variable* var = expr->var(); | |
1006 AsmTyper::StandardMember standard_object = | |
1007 typer_->VariableAsStandardMember(var); | |
1008 ZoneList<Expression*>* args = call->arguments(); | |
1009 LocalType call_type = TypeOf(call); | |
1010 | |
1011 switch (standard_object) { | |
1012 case AsmTyper::kNone: { | |
1013 return false; | |
1014 } | |
1015 case AsmTyper::kMathAcos: { | |
1016 VisitCallArgs(call); | |
1017 DCHECK_EQ(kAstF64, call_type); | |
1018 current_function_builder_->Emit(kExprF64Acos); | |
1019 break; | |
1020 } | |
1021 case AsmTyper::kMathAsin: { | |
1022 VisitCallArgs(call); | |
1023 DCHECK_EQ(kAstF64, call_type); | |
1024 current_function_builder_->Emit(kExprF64Asin); | |
1025 break; | |
1026 } | |
1027 case AsmTyper::kMathAtan: { | |
1028 VisitCallArgs(call); | |
1029 DCHECK_EQ(kAstF64, call_type); | |
1030 current_function_builder_->Emit(kExprF64Atan); | |
1031 break; | |
1032 } | |
1033 case AsmTyper::kMathCos: { | |
1034 VisitCallArgs(call); | |
1035 DCHECK_EQ(kAstF64, call_type); | |
1036 current_function_builder_->Emit(kExprF64Cos); | |
1037 break; | |
1038 } | |
1039 case AsmTyper::kMathSin: { | |
1040 VisitCallArgs(call); | |
1041 DCHECK_EQ(kAstF64, call_type); | |
1042 current_function_builder_->Emit(kExprF64Sin); | |
1043 break; | |
1044 } | |
1045 case AsmTyper::kMathTan: { | |
1046 VisitCallArgs(call); | |
1047 DCHECK_EQ(kAstF64, call_type); | |
1048 current_function_builder_->Emit(kExprF64Tan); | |
1049 break; | |
1050 } | |
1051 case AsmTyper::kMathExp: { | |
1052 VisitCallArgs(call); | |
1053 DCHECK_EQ(kAstF64, call_type); | |
1054 current_function_builder_->Emit(kExprF64Exp); | |
1055 break; | |
1056 } | |
1057 case AsmTyper::kMathLog: { | |
1058 VisitCallArgs(call); | |
1059 DCHECK_EQ(kAstF64, call_type); | |
1060 current_function_builder_->Emit(kExprF64Log); | |
1061 break; | |
1062 } | |
1063 case AsmTyper::kMathCeil: { | |
1064 VisitCallArgs(call); | |
1065 if (call_type == kAstF32) { | |
1066 current_function_builder_->Emit(kExprF32Ceil); | |
1067 } else if (call_type == kAstF64) { | |
1068 current_function_builder_->Emit(kExprF64Ceil); | |
1069 } else { | |
1070 UNREACHABLE(); | |
1071 } | |
1072 break; | |
1073 } | |
1074 case AsmTyper::kMathFloor: { | |
1075 VisitCallArgs(call); | |
1076 if (call_type == kAstF32) { | |
1077 current_function_builder_->Emit(kExprF32Floor); | |
1078 } else if (call_type == kAstF64) { | |
1079 current_function_builder_->Emit(kExprF64Floor); | |
1080 } else { | |
1081 UNREACHABLE(); | |
1082 } | |
1083 break; | |
1084 } | |
1085 case AsmTyper::kMathSqrt: { | |
1086 VisitCallArgs(call); | |
1087 if (call_type == kAstF32) { | |
1088 current_function_builder_->Emit(kExprF32Sqrt); | |
1089 } else if (call_type == kAstF64) { | |
1090 current_function_builder_->Emit(kExprF64Sqrt); | |
1091 } else { | |
1092 UNREACHABLE(); | |
1093 } | |
1094 break; | |
1095 } | |
1096 case AsmTyper::kMathAbs: { | |
1097 if (call_type == kAstI32) { | |
1098 uint32_t tmp = current_function_builder_->AddLocal(kAstI32); | |
1099 | |
1100 // if set_local(tmp, x) < 0 | |
1101 Visit(call->arguments()->at(0)); | |
1102 current_function_builder_->EmitSetLocal(tmp); | |
1103 byte code[] = {WASM_I8(0)}; | |
1104 current_function_builder_->EmitCode(code, sizeof(code)); | |
1105 current_function_builder_->Emit(kExprI32LtS); | |
1106 current_function_builder_->Emit(kExprIf); | |
1107 | |
1108 // then (0 - tmp) | |
1109 current_function_builder_->EmitCode(code, sizeof(code)); | |
1110 current_function_builder_->EmitGetLocal(tmp); | |
1111 current_function_builder_->Emit(kExprI32Sub); | |
1112 | |
1113 // else tmp | |
1114 current_function_builder_->Emit(kExprElse); | |
1115 current_function_builder_->EmitGetLocal(tmp); | |
1116 // end | |
1117 current_function_builder_->Emit(kExprEnd); | |
1118 | |
1119 } else if (call_type == kAstF32) { | |
1120 VisitCallArgs(call); | |
1121 current_function_builder_->Emit(kExprF32Abs); | |
1122 } else if (call_type == kAstF64) { | |
1123 VisitCallArgs(call); | |
1124 current_function_builder_->Emit(kExprF64Abs); | |
1125 } else { | |
1126 UNREACHABLE(); | |
1127 } | |
1128 break; | |
1129 } | |
1130 case AsmTyper::kMathMin: { | |
1131 // TODO(bradnelson): Change wasm to match Math.min in asm.js mode. | |
1132 if (call_type == kAstI32) { | |
1133 uint32_t tmp_x = current_function_builder_->AddLocal(kAstI32); | |
1134 uint32_t tmp_y = current_function_builder_->AddLocal(kAstI32); | |
1135 | |
1136 // if set_local(tmp_x, x) < set_local(tmp_y, y) | |
1137 Visit(call->arguments()->at(0)); | |
1138 current_function_builder_->EmitSetLocal(tmp_x); | |
1139 | |
1140 Visit(call->arguments()->at(1)); | |
1141 current_function_builder_->EmitSetLocal(tmp_y); | |
1142 | |
1143 current_function_builder_->Emit(kExprI32LeS); | |
1144 current_function_builder_->Emit(kExprIf); | |
1145 | |
1146 // then tmp_x | |
1147 current_function_builder_->EmitGetLocal(tmp_x); | |
1148 | |
1149 // else tmp_y | |
1150 current_function_builder_->Emit(kExprElse); | |
1151 current_function_builder_->EmitGetLocal(tmp_y); | |
1152 current_function_builder_->Emit(kExprEnd); | |
1153 | |
1154 } else if (call_type == kAstF32) { | |
1155 VisitCallArgs(call); | |
1156 current_function_builder_->Emit(kExprF32Min); | |
1157 } else if (call_type == kAstF64) { | |
1158 VisitCallArgs(call); | |
1159 current_function_builder_->Emit(kExprF64Min); | |
1160 } else { | |
1161 UNREACHABLE(); | |
1162 } | |
1163 break; | |
1164 } | |
1165 case AsmTyper::kMathMax: { | |
1166 // TODO(bradnelson): Change wasm to match Math.max in asm.js mode. | |
1167 if (call_type == kAstI32) { | |
1168 uint32_t tmp_x = current_function_builder_->AddLocal(kAstI32); | |
1169 uint32_t tmp_y = current_function_builder_->AddLocal(kAstI32); | |
1170 | |
1171 // if set_local(tmp_x, x) < set_local(tmp_y, y) | |
1172 Visit(call->arguments()->at(0)); | |
1173 | |
1174 current_function_builder_->EmitSetLocal(tmp_x); | |
1175 | |
1176 Visit(call->arguments()->at(1)); | |
1177 current_function_builder_->EmitSetLocal(tmp_y); | |
1178 | |
1179 current_function_builder_->Emit(kExprI32LeS); | |
1180 current_function_builder_->Emit(kExprIf); | |
1181 | |
1182 // then tmp_y | |
1183 current_function_builder_->EmitGetLocal(tmp_y); | |
1184 | |
1185 // else tmp_x | |
1186 current_function_builder_->Emit(kExprElse); | |
1187 current_function_builder_->EmitGetLocal(tmp_x); | |
1188 current_function_builder_->Emit(kExprEnd); | |
1189 | |
1190 } else if (call_type == kAstF32) { | |
1191 VisitCallArgs(call); | |
1192 current_function_builder_->Emit(kExprF32Max); | |
1193 } else if (call_type == kAstF64) { | |
1194 VisitCallArgs(call); | |
1195 current_function_builder_->Emit(kExprF64Max); | |
1196 } else { | |
1197 UNREACHABLE(); | |
1198 } | |
1199 break; | |
1200 } | |
1201 case AsmTyper::kMathAtan2: { | |
1202 VisitCallArgs(call); | |
1203 DCHECK_EQ(kAstF64, call_type); | |
1204 current_function_builder_->Emit(kExprF64Atan2); | |
1205 break; | |
1206 } | |
1207 case AsmTyper::kMathPow: { | |
1208 VisitCallArgs(call); | |
1209 DCHECK_EQ(kAstF64, call_type); | |
1210 current_function_builder_->Emit(kExprF64Pow); | |
1211 break; | |
1212 } | |
1213 case AsmTyper::kMathImul: { | |
1214 VisitCallArgs(call); | |
1215 current_function_builder_->Emit(kExprI32Mul); | |
1216 break; | |
1217 } | |
1218 case AsmTyper::kMathFround: { | |
1219 DCHECK(args->length() == 1); | |
1220 Literal* literal = args->at(0)->AsLiteral(); | |
1221 if (literal != nullptr) { | |
1222 // constant fold Math.fround(#const); | |
1223 if (literal->raw_value()->IsNumber()) { | |
1224 float val = static_cast<float>(literal->raw_value()->AsNumber()); | |
1225 byte code[] = {WASM_F32(val)}; | |
1226 current_function_builder_->EmitCode(code, sizeof(code)); | |
1227 return true; | |
1228 } | |
1229 } | |
1230 VisitCallArgs(call); | |
1231 switch (TypeIndexOf(args->at(0))) { | |
1232 case kInt32: | |
1233 case kFixnum: | |
1234 current_function_builder_->Emit(kExprF32SConvertI32); | |
1235 break; | |
1236 case kUint32: | |
1237 current_function_builder_->Emit(kExprF32UConvertI32); | |
1238 break; | |
1239 case kFloat32: | |
1240 break; | |
1241 case kFloat64: | |
1242 current_function_builder_->Emit(kExprF32ConvertF64); | |
1243 break; | |
1244 default: | |
1245 UNREACHABLE(); | |
1246 } | |
1247 break; | |
1248 } | |
1249 default: { | |
1250 UNREACHABLE(); | |
1251 break; | |
1252 } | |
1253 } | |
1254 return true; | |
1255 } | |
1256 | |
1257 void VisitCallArgs(Call* expr) { | |
1258 ZoneList<Expression*>* args = expr->arguments(); | |
1259 for (int i = 0; i < args->length(); ++i) { | |
1260 Expression* arg = args->at(i); | |
1261 RECURSE(Visit(arg)); | |
1262 } | |
1263 } | |
1264 | |
1265 void VisitCall(Call* expr) override { | |
1266 Call::CallType call_type = expr->GetCallType(isolate_); | |
1267 switch (call_type) { | |
1268 case Call::OTHER_CALL: { | |
1269 DCHECK_EQ(kFuncScope, scope_); | |
1270 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | |
1271 if (proxy != nullptr) { | |
1272 if (VisitStdlibFunction(expr, proxy)) { | |
1273 return; | |
1274 } | |
1275 } | |
1276 uint32_t index; | |
1277 VariableProxy* vp = expr->expression()->AsVariableProxy(); | |
1278 if (vp != nullptr && | |
1279 Type::Any()->Is(bounds_->get(vp).lower->AsFunction()->Result())) { | |
1280 LocalType return_type = TypeOf(expr); | |
1281 ZoneList<Expression*>* args = expr->arguments(); | |
1282 FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1, | |
1283 args->length()); | |
1284 if (return_type != kAstStmt) { | |
1285 sig.AddReturn(return_type); | |
1286 } | |
1287 for (int i = 0; i < args->length(); ++i) { | |
1288 sig.AddParam(TypeOf(args->at(i))); | |
1289 } | |
1290 index = | |
1291 imported_function_table_.GetFunctionIndex(vp->var(), sig.Build()); | |
1292 VisitCallArgs(expr); | |
1293 current_function_builder_->Emit(kExprCallImport); | |
1294 current_function_builder_->EmitVarInt(expr->arguments()->length()); | |
1295 current_function_builder_->EmitVarInt(index); | |
1296 } else { | |
1297 index = LookupOrInsertFunction(vp->var()); | |
1298 VisitCallArgs(expr); | |
1299 current_function_builder_->Emit(kExprCallFunction); | |
1300 current_function_builder_->EmitVarInt(expr->arguments()->length()); | |
1301 current_function_builder_->EmitVarInt(index); | |
1302 } | |
1303 break; | |
1304 } | |
1305 case Call::KEYED_PROPERTY_CALL: { | |
1306 DCHECK_EQ(kFuncScope, scope_); | |
1307 Property* p = expr->expression()->AsProperty(); | |
1308 DCHECK_NOT_NULL(p); | |
1309 VariableProxy* var = p->obj()->AsVariableProxy(); | |
1310 DCHECK_NOT_NULL(var); | |
1311 FunctionTableIndices* indices = LookupFunctionTable(var->var()); | |
1312 RECURSE(Visit(p->key())); | |
1313 current_function_builder_->EmitI32Const(indices->start_index); | |
1314 current_function_builder_->Emit(kExprI32Add); | |
1315 VisitCallArgs(expr); | |
1316 current_function_builder_->Emit(kExprCallIndirect); | |
1317 current_function_builder_->EmitVarInt(expr->arguments()->length()); | |
1318 current_function_builder_->EmitVarInt(indices->signature_index); | |
1319 break; | |
1320 } | |
1321 default: | |
1322 UNREACHABLE(); | |
1323 } | |
1324 } | |
1325 | |
1326 void VisitCallNew(CallNew* expr) override { UNREACHABLE(); } | |
1327 | |
1328 void VisitCallRuntime(CallRuntime* expr) override { UNREACHABLE(); } | |
1329 | |
1330 void VisitUnaryOperation(UnaryOperation* expr) override { | |
1331 RECURSE(Visit(expr->expression())); | |
1332 switch (expr->op()) { | |
1333 case Token::NOT: { | |
1334 DCHECK_EQ(kAstI32, TypeOf(expr->expression())); | |
1335 current_function_builder_->Emit(kExprI32Eqz); | |
1336 break; | |
1337 } | |
1338 default: | |
1339 UNREACHABLE(); | |
1340 } | |
1341 } | |
1342 | |
1343 void VisitCountOperation(CountOperation* expr) override { UNREACHABLE(); } | |
1344 | |
1345 bool MatchIntBinaryOperation(BinaryOperation* expr, Token::Value op, | |
1346 int32_t val) { | |
1347 DCHECK_NOT_NULL(expr->right()); | |
1348 if (expr->op() == op && expr->right()->IsLiteral() && | |
1349 TypeOf(expr) == kAstI32) { | |
1350 Literal* right = expr->right()->AsLiteral(); | |
1351 DCHECK(right->raw_value()->IsNumber()); | |
1352 if (static_cast<int32_t>(right->raw_value()->AsNumber()) == val) { | |
1353 return true; | |
1354 } | |
1355 } | |
1356 return false; | |
1357 } | |
1358 | |
1359 bool MatchDoubleBinaryOperation(BinaryOperation* expr, Token::Value op, | |
1360 double val) { | |
1361 DCHECK_NOT_NULL(expr->right()); | |
1362 if (expr->op() == op && expr->right()->IsLiteral() && | |
1363 TypeOf(expr) == kAstF64) { | |
1364 Literal* right = expr->right()->AsLiteral(); | |
1365 DCHECK(right->raw_value()->IsNumber()); | |
1366 if (right->raw_value()->AsNumber() == val) { | |
1367 return true; | |
1368 } | |
1369 } | |
1370 return false; | |
1371 } | |
1372 | |
1373 enum ConvertOperation { kNone, kAsIs, kToInt, kToDouble }; | |
1374 | |
1375 ConvertOperation MatchOr(BinaryOperation* expr) { | |
1376 if (MatchIntBinaryOperation(expr, Token::BIT_OR, 0) && | |
1377 (TypeOf(expr->left()) == kAstI32)) { | |
1378 return kAsIs; | |
1379 } else { | |
1380 return kNone; | |
1381 } | |
1382 } | |
1383 | |
1384 ConvertOperation MatchShr(BinaryOperation* expr) { | |
1385 if (MatchIntBinaryOperation(expr, Token::SHR, 0)) { | |
1386 // TODO(titzer): this probably needs to be kToUint | |
1387 return (TypeOf(expr->left()) == kAstI32) ? kAsIs : kToInt; | |
1388 } else { | |
1389 return kNone; | |
1390 } | |
1391 } | |
1392 | |
1393 ConvertOperation MatchXor(BinaryOperation* expr) { | |
1394 if (MatchIntBinaryOperation(expr, Token::BIT_XOR, 0xffffffff)) { | |
1395 DCHECK_EQ(kAstI32, TypeOf(expr->left())); | |
1396 DCHECK_EQ(kAstI32, TypeOf(expr->right())); | |
1397 BinaryOperation* op = expr->left()->AsBinaryOperation(); | |
1398 if (op != nullptr) { | |
1399 if (MatchIntBinaryOperation(op, Token::BIT_XOR, 0xffffffff)) { | |
1400 DCHECK_EQ(kAstI32, TypeOf(op->right())); | |
1401 if (TypeOf(op->left()) != kAstI32) { | |
1402 return kToInt; | |
1403 } else { | |
1404 return kAsIs; | |
1405 } | |
1406 } | |
1407 } | |
1408 } | |
1409 return kNone; | |
1410 } | |
1411 | |
1412 ConvertOperation MatchMul(BinaryOperation* expr) { | |
1413 if (MatchDoubleBinaryOperation(expr, Token::MUL, 1.0)) { | |
1414 DCHECK_EQ(kAstF64, TypeOf(expr->right())); | |
1415 if (TypeOf(expr->left()) != kAstF64) { | |
1416 return kToDouble; | |
1417 } else { | |
1418 return kAsIs; | |
1419 } | |
1420 } else { | |
1421 return kNone; | |
1422 } | |
1423 } | |
1424 | |
1425 ConvertOperation MatchBinaryOperation(BinaryOperation* expr) { | |
1426 switch (expr->op()) { | |
1427 case Token::BIT_OR: | |
1428 return MatchOr(expr); | |
1429 case Token::SHR: | |
1430 return MatchShr(expr); | |
1431 case Token::BIT_XOR: | |
1432 return MatchXor(expr); | |
1433 case Token::MUL: | |
1434 return MatchMul(expr); | |
1435 default: | |
1436 return kNone; | |
1437 } | |
1438 } | |
1439 | |
1440 // Work around Mul + Div being defined in PPC assembler. | |
1441 #ifdef Mul | |
1442 #undef Mul | |
1443 #endif | |
1444 | |
1445 #define NON_SIGNED_BINOP(op) \ | |
1446 static WasmOpcode opcodes[] = { \ | |
1447 kExprI32##op, \ | |
1448 kExprI32##op, \ | |
1449 kExprF32##op, \ | |
1450 kExprF64##op \ | |
1451 } | |
1452 | |
1453 #define SIGNED_BINOP(op) \ | |
1454 static WasmOpcode opcodes[] = { \ | |
1455 kExprI32##op##S, \ | |
1456 kExprI32##op##U, \ | |
1457 kExprF32##op, \ | |
1458 kExprF64##op \ | |
1459 } | |
1460 | |
1461 #define NON_SIGNED_INT_BINOP(op) \ | |
1462 static WasmOpcode opcodes[] = { kExprI32##op, kExprI32##op } | |
1463 | |
1464 #define BINOP_CASE(token, op, V, ignore_sign) \ | |
1465 case token: { \ | |
1466 V(op); \ | |
1467 int type = TypeIndexOf(expr->left(), expr->right(), ignore_sign); \ | |
1468 current_function_builder_->Emit(opcodes[type]); \ | |
1469 break; \ | |
1470 } | |
1471 | |
1472 Expression* GetLeft(BinaryOperation* expr) { | |
1473 if (expr->op() == Token::BIT_XOR) { | |
1474 return expr->left()->AsBinaryOperation()->left(); | |
1475 } else { | |
1476 return expr->left(); | |
1477 } | |
1478 } | |
1479 | |
1480 void VisitBinaryOperation(BinaryOperation* expr) override { | |
1481 ConvertOperation convertOperation = MatchBinaryOperation(expr); | |
1482 if (convertOperation == kToDouble) { | |
1483 RECURSE(Visit(expr->left())); | |
1484 TypeIndex type = TypeIndexOf(expr->left()); | |
1485 if (type == kInt32 || type == kFixnum) { | |
1486 current_function_builder_->Emit(kExprF64SConvertI32); | |
1487 } else if (type == kUint32) { | |
1488 current_function_builder_->Emit(kExprF64UConvertI32); | |
1489 } else if (type == kFloat32) { | |
1490 current_function_builder_->Emit(kExprF64ConvertF32); | |
1491 } else { | |
1492 UNREACHABLE(); | |
1493 } | |
1494 } else if (convertOperation == kToInt) { | |
1495 RECURSE(Visit(GetLeft(expr))); | |
1496 TypeIndex type = TypeIndexOf(GetLeft(expr)); | |
1497 if (type == kFloat32) { | |
1498 current_function_builder_->Emit(kExprI32AsmjsSConvertF32); | |
1499 } else if (type == kFloat64) { | |
1500 current_function_builder_->Emit(kExprI32AsmjsSConvertF64); | |
1501 } else { | |
1502 UNREACHABLE(); | |
1503 } | |
1504 } else if (convertOperation == kAsIs) { | |
1505 RECURSE(Visit(GetLeft(expr))); | |
1506 } else { | |
1507 if (expr->op() == Token::COMMA) { | |
1508 current_function_builder_->Emit(kExprBlock); | |
1509 } | |
1510 | |
1511 RECURSE(Visit(expr->left())); | |
1512 RECURSE(Visit(expr->right())); | |
1513 | |
1514 if (expr->op() == Token::COMMA) { | |
1515 current_function_builder_->Emit(kExprEnd); | |
1516 } | |
1517 | |
1518 switch (expr->op()) { | |
1519 BINOP_CASE(Token::ADD, Add, NON_SIGNED_BINOP, true); | |
1520 BINOP_CASE(Token::SUB, Sub, NON_SIGNED_BINOP, true); | |
1521 BINOP_CASE(Token::MUL, Mul, NON_SIGNED_BINOP, true); | |
1522 BINOP_CASE(Token::BIT_OR, Ior, NON_SIGNED_INT_BINOP, true); | |
1523 BINOP_CASE(Token::BIT_AND, And, NON_SIGNED_INT_BINOP, true); | |
1524 BINOP_CASE(Token::BIT_XOR, Xor, NON_SIGNED_INT_BINOP, true); | |
1525 BINOP_CASE(Token::SHL, Shl, NON_SIGNED_INT_BINOP, true); | |
1526 BINOP_CASE(Token::SAR, ShrS, NON_SIGNED_INT_BINOP, true); | |
1527 BINOP_CASE(Token::SHR, ShrU, NON_SIGNED_INT_BINOP, true); | |
1528 case Token::DIV: { | |
1529 static WasmOpcode opcodes[] = {kExprI32AsmjsDivS, kExprI32AsmjsDivU, | |
1530 kExprF32Div, kExprF64Div}; | |
1531 int type = TypeIndexOf(expr->left(), expr->right(), false); | |
1532 current_function_builder_->Emit(opcodes[type]); | |
1533 break; | |
1534 } | |
1535 case Token::MOD: { | |
1536 TypeIndex type = TypeIndexOf(expr->left(), expr->right(), false); | |
1537 if (type == kInt32) { | |
1538 current_function_builder_->Emit(kExprI32AsmjsRemS); | |
1539 } else if (type == kUint32) { | |
1540 current_function_builder_->Emit(kExprI32AsmjsRemU); | |
1541 } else if (type == kFloat64) { | |
1542 current_function_builder_->Emit(kExprF64Mod); | |
1543 return; | |
1544 } else { | |
1545 UNREACHABLE(); | |
1546 } | |
1547 break; | |
1548 } | |
1549 case Token::COMMA: { | |
1550 break; | |
1551 } | |
1552 default: | |
1553 UNREACHABLE(); | |
1554 } | |
1555 } | |
1556 } | |
1557 | |
1558 void VisitCompareOperation(CompareOperation* expr) override { | |
1559 RECURSE(Visit(expr->left())); | |
1560 RECURSE(Visit(expr->right())); | |
1561 switch (expr->op()) { | |
1562 BINOP_CASE(Token::EQ, Eq, NON_SIGNED_BINOP, false); | |
1563 BINOP_CASE(Token::LT, Lt, SIGNED_BINOP, false); | |
1564 BINOP_CASE(Token::LTE, Le, SIGNED_BINOP, false); | |
1565 BINOP_CASE(Token::GT, Gt, SIGNED_BINOP, false); | |
1566 BINOP_CASE(Token::GTE, Ge, SIGNED_BINOP, false); | |
1567 default: | |
1568 UNREACHABLE(); | |
1569 } | |
1570 } | |
1571 | |
1572 #undef BINOP_CASE | |
1573 #undef NON_SIGNED_INT_BINOP | |
1574 #undef SIGNED_BINOP | |
1575 #undef NON_SIGNED_BINOP | |
1576 | |
1577 enum TypeIndex { | |
1578 kInt32 = 0, | |
1579 kUint32 = 1, | |
1580 kFloat32 = 2, | |
1581 kFloat64 = 3, | |
1582 kFixnum = 4 | |
1583 }; | |
1584 | |
1585 TypeIndex TypeIndexOf(Expression* left, Expression* right, bool ignore_sign) { | |
1586 TypeIndex left_index = TypeIndexOf(left); | |
1587 TypeIndex right_index = TypeIndexOf(right); | |
1588 if (left_index == kFixnum) { | |
1589 left_index = right_index; | |
1590 } | |
1591 if (right_index == kFixnum) { | |
1592 right_index = left_index; | |
1593 } | |
1594 if (left_index == kFixnum && right_index == kFixnum) { | |
1595 left_index = kInt32; | |
1596 right_index = kInt32; | |
1597 } | |
1598 DCHECK((left_index == right_index) || | |
1599 (ignore_sign && (left_index <= 1) && (right_index <= 1))); | |
1600 return left_index; | |
1601 } | |
1602 | |
1603 TypeIndex TypeIndexOf(Expression* expr) { | |
1604 DCHECK_EQ(bounds_->get(expr).lower, bounds_->get(expr).upper); | |
1605 Type* type = bounds_->get(expr).lower; | |
1606 if (type->Is(cache_.kAsmFixnum)) { | |
1607 return kFixnum; | |
1608 } else if (type->Is(cache_.kAsmSigned)) { | |
1609 return kInt32; | |
1610 } else if (type->Is(cache_.kAsmUnsigned)) { | |
1611 return kUint32; | |
1612 } else if (type->Is(cache_.kAsmInt)) { | |
1613 return kInt32; | |
1614 } else if (type->Is(cache_.kAsmFloat)) { | |
1615 return kFloat32; | |
1616 } else if (type->Is(cache_.kAsmDouble)) { | |
1617 return kFloat64; | |
1618 } else { | |
1619 UNREACHABLE(); | |
1620 return kInt32; | |
1621 } | |
1622 } | |
1623 | |
1624 #undef CASE | |
1625 #undef NON_SIGNED_INT | |
1626 #undef SIGNED | |
1627 #undef NON_SIGNED | |
1628 | |
1629 void VisitThisFunction(ThisFunction* expr) override { UNREACHABLE(); } | |
1630 | |
1631 void VisitDeclarations(ZoneList<Declaration*>* decls) override { | |
1632 for (int i = 0; i < decls->length(); ++i) { | |
1633 Declaration* decl = decls->at(i); | |
1634 RECURSE(Visit(decl)); | |
1635 } | |
1636 } | |
1637 | |
1638 void VisitClassLiteral(ClassLiteral* expr) override { UNREACHABLE(); } | |
1639 | |
1640 void VisitSpread(Spread* expr) override { UNREACHABLE(); } | |
1641 | |
1642 void VisitSuperPropertyReference(SuperPropertyReference* expr) override { | |
1643 UNREACHABLE(); | |
1644 } | |
1645 | |
1646 void VisitSuperCallReference(SuperCallReference* expr) override { | |
1647 UNREACHABLE(); | |
1648 } | |
1649 | |
1650 void VisitSloppyBlockFunctionStatement( | |
1651 SloppyBlockFunctionStatement* expr) override { | |
1652 UNREACHABLE(); | |
1653 } | |
1654 | |
1655 void VisitDoExpression(DoExpression* expr) override { UNREACHABLE(); } | |
1656 | |
1657 void VisitRewritableExpression(RewritableExpression* expr) override { | |
1658 UNREACHABLE(); | |
1659 } | |
1660 | |
1661 struct IndexContainer : public ZoneObject { | |
1662 uint32_t index; | |
1663 }; | |
1664 | |
1665 uint32_t LookupOrInsertLocal(Variable* v, LocalType type) { | |
1666 DCHECK_NOT_NULL(current_function_builder_); | |
1667 ZoneHashMap::Entry* entry = | |
1668 local_variables_.Lookup(v, ComputePointerHash(v)); | |
1669 if (entry == nullptr) { | |
1670 uint32_t index; | |
1671 DCHECK(!v->IsParameter()); | |
1672 index = current_function_builder_->AddLocal(type); | |
1673 IndexContainer* container = new (zone()) IndexContainer(); | |
1674 container->index = index; | |
1675 entry = local_variables_.LookupOrInsert(v, ComputePointerHash(v), | |
1676 ZoneAllocationPolicy(zone())); | |
1677 entry->value = container; | |
1678 } | |
1679 return (reinterpret_cast<IndexContainer*>(entry->value))->index; | |
1680 } | |
1681 | |
1682 void InsertParameter(Variable* v, LocalType type, uint32_t index) { | |
1683 DCHECK(v->IsParameter()); | |
1684 DCHECK_NOT_NULL(current_function_builder_); | |
1685 ZoneHashMap::Entry* entry = | |
1686 local_variables_.Lookup(v, ComputePointerHash(v)); | |
1687 DCHECK_NULL(entry); | |
1688 IndexContainer* container = new (zone()) IndexContainer(); | |
1689 container->index = index; | |
1690 entry = local_variables_.LookupOrInsert(v, ComputePointerHash(v), | |
1691 ZoneAllocationPolicy(zone())); | |
1692 entry->value = container; | |
1693 } | |
1694 | |
1695 uint32_t LookupOrInsertGlobal(Variable* v, LocalType type) { | |
1696 ZoneHashMap::Entry* entry = | |
1697 global_variables_.Lookup(v, ComputePointerHash(v)); | |
1698 if (entry == nullptr) { | |
1699 uint32_t index = | |
1700 builder_->AddGlobal(WasmOpcodes::MachineTypeFor(type), 0); | |
1701 IndexContainer* container = new (zone()) IndexContainer(); | |
1702 container->index = index; | |
1703 entry = global_variables_.LookupOrInsert(v, ComputePointerHash(v), | |
1704 ZoneAllocationPolicy(zone())); | |
1705 entry->value = container; | |
1706 } | |
1707 return (reinterpret_cast<IndexContainer*>(entry->value))->index; | |
1708 } | |
1709 | |
1710 uint32_t LookupOrInsertFunction(Variable* v) { | |
1711 DCHECK_NOT_NULL(builder_); | |
1712 ZoneHashMap::Entry* entry = functions_.Lookup(v, ComputePointerHash(v)); | |
1713 if (entry == nullptr) { | |
1714 uint32_t index = builder_->AddFunction(); | |
1715 IndexContainer* container = new (zone()) IndexContainer(); | |
1716 container->index = index; | |
1717 entry = functions_.LookupOrInsert(v, ComputePointerHash(v), | |
1718 ZoneAllocationPolicy(zone())); | |
1719 entry->value = container; | |
1720 } | |
1721 return (reinterpret_cast<IndexContainer*>(entry->value))->index; | |
1722 } | |
1723 | |
1724 LocalType TypeOf(Expression* expr) { | |
1725 DCHECK_EQ(bounds_->get(expr).lower, bounds_->get(expr).upper); | |
1726 return TypeFrom(bounds_->get(expr).lower); | |
1727 } | |
1728 | |
1729 LocalType TypeFrom(Type* type) { | |
1730 if (type->Is(cache_.kAsmInt)) { | |
1731 return kAstI32; | |
1732 } else if (type->Is(cache_.kAsmFloat)) { | |
1733 return kAstF32; | |
1734 } else if (type->Is(cache_.kAsmDouble)) { | |
1735 return kAstF64; | |
1736 } else { | |
1737 return kAstStmt; | |
1738 } | |
1739 } | |
1740 | |
1741 Zone* zone() { return zone_; } | |
1742 | |
1743 ZoneHashMap local_variables_; | |
1744 ZoneHashMap functions_; | |
1745 ZoneHashMap global_variables_; | |
1746 AsmScope scope_; | |
1747 WasmModuleBuilder* builder_; | |
1748 WasmFunctionBuilder* current_function_builder_; | |
1749 FunctionLiteral* literal_; | |
1750 Isolate* isolate_; | |
1751 Zone* zone_; | |
1752 AsmTyper* typer_; | |
1753 TypeCache const& cache_; | |
1754 ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_; | |
1755 ZoneVector<ForeignVariable> foreign_variables_; | |
1756 uint32_t init_function_index_; | |
1757 uint32_t foreign_init_function_index_; | |
1758 uint32_t next_table_index_; | |
1759 ZoneHashMap function_tables_; | |
1760 ImportedFunctionTable imported_function_table_; | |
1761 const AstTypeBounds* bounds_; | |
1762 | |
1763 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); | |
1764 | |
1765 private: | |
1766 DISALLOW_COPY_AND_ASSIGN(AsmWasmBuilderImpl); | |
1767 }; | |
1768 | |
1769 AsmWasmBuilder::AsmWasmBuilder(Isolate* isolate, Zone* zone, | |
1770 FunctionLiteral* literal, AsmTyper* typer) | |
1771 : isolate_(isolate), zone_(zone), literal_(literal), typer_(typer) {} | |
1772 | |
1773 // TODO(aseemgarg): probably should take zone (to write wasm to) as input so | |
1774 // that zone in constructor may be thrown away once wasm module is written. | |
1775 ZoneBuffer* AsmWasmBuilder::Run(i::Handle<i::FixedArray>* foreign_args) { | |
1776 AsmWasmBuilderImpl impl(isolate_, zone_, literal_, typer_); | |
1777 impl.Build(); | |
1778 *foreign_args = impl.GetForeignArgs(); | |
1779 ZoneBuffer* buffer = new (zone_) ZoneBuffer(zone_); | |
1780 impl.builder_->WriteTo(*buffer); | |
1781 return buffer; | |
1782 } | |
1783 } // namespace wasm | |
1784 } // namespace internal | |
1785 } // namespace v8 | |
OLD | NEW |