Line data Source code
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/asmjs/asm-types.h"
14 : #include "src/asmjs/asm-wasm-builder.h"
15 : #include "src/asmjs/switch-logic.h"
16 :
17 : #include "src/wasm/wasm-opcodes.h"
18 :
19 : #include "src/ast/ast.h"
20 : #include "src/ast/scopes.h"
21 : #include "src/codegen.h"
22 : #include "src/compilation-info.h"
23 : #include "src/compiler.h"
24 : #include "src/counters.h"
25 : #include "src/isolate.h"
26 : #include "src/objects-inl.h"
27 : #include "src/parsing/parse-info.h"
28 :
29 : namespace v8 {
30 : namespace internal {
31 : namespace wasm {
32 :
33 : #define RECURSE(call) \
34 : do { \
35 : DCHECK(!HasStackOverflow()); \
36 : call; \
37 : if (HasStackOverflow()) return; \
38 : } while (false)
39 :
40 : namespace {
41 :
42 : enum AsmScope { kModuleScope, kInitScope, kFuncScope, kExportScope };
43 : enum ValueFate { kDrop, kLeaveOnStack };
44 :
45 : struct ForeignVariable {
46 : Handle<Name> name;
47 : Variable* var;
48 : ValueType type;
49 : };
50 :
51 : enum TargetType : uint8_t { NoTarget, BreakTarget, ContinueTarget };
52 :
53 : } // namespace
54 :
55 : class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
56 : public:
57 3532 : AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, CompilationInfo* info,
58 : AstValueFactory* ast_value_factory, Handle<Script> script,
59 : FunctionLiteral* literal, AsmTyper* typer)
60 : : local_variables_(ZoneHashMap::kDefaultHashMapCapacity,
61 : ZoneAllocationPolicy(zone)),
62 : functions_(ZoneHashMap::kDefaultHashMapCapacity,
63 : ZoneAllocationPolicy(zone)),
64 : global_variables_(ZoneHashMap::kDefaultHashMapCapacity,
65 : ZoneAllocationPolicy(zone)),
66 : scope_(kModuleScope),
67 3532 : builder_(new (zone) WasmModuleBuilder(zone)),
68 : current_function_builder_(nullptr),
69 : literal_(literal),
70 : isolate_(isolate),
71 : zone_(zone),
72 : info_(info),
73 : ast_value_factory_(ast_value_factory),
74 : script_(script),
75 : typer_(typer),
76 : typer_failed_(false),
77 : typer_finished_(false),
78 : breakable_blocks_(zone),
79 : foreign_variables_(zone),
80 : init_function_(nullptr),
81 : foreign_init_function_(nullptr),
82 : function_tables_(ZoneHashMap::kDefaultHashMapCapacity,
83 : ZoneAllocationPolicy(zone)),
84 : imported_function_table_(this),
85 14128 : parent_binop_(nullptr) {
86 : InitializeAstVisitor(isolate);
87 3532 : }
88 :
89 3532 : void InitializeInitFunction() {
90 : FunctionSig::Builder b(zone(), 0, 0);
91 3532 : init_function_ = builder_->AddFunction(b.Build());
92 3532 : builder_->MarkStartFunction(init_function_);
93 : // Record start of the function, used as position for the stack check.
94 3532 : init_function_->SetAsmFunctionStartPosition(literal_->start_position());
95 3532 : }
96 :
97 6134 : void BuildForeignInitFunction() {
98 3067 : foreign_init_function_ = builder_->AddFunction();
99 7034 : FunctionSig::Builder b(zone(), 0, foreign_variables_.size());
100 6584 : for (auto i = foreign_variables_.begin(); i != foreign_variables_.end();
101 : ++i) {
102 450 : b.AddParam(i->type);
103 : }
104 : foreign_init_function_->ExportAs(
105 6134 : CStrVector(AsmWasmBuilder::foreign_init_name));
106 3067 : foreign_init_function_->SetSignature(b.Build());
107 7034 : for (size_t pos = 0; pos < foreign_variables_.size(); ++pos) {
108 450 : foreign_init_function_->EmitGetLocal(static_cast<uint32_t>(pos));
109 : ForeignVariable* fv = &foreign_variables_[pos];
110 450 : uint32_t index = LookupOrInsertGlobal(fv->var, fv->type);
111 450 : foreign_init_function_->EmitWithU32V(kExprSetGlobal, index);
112 : }
113 3067 : foreign_init_function_->Emit(kExprEnd);
114 3067 : }
115 :
116 3067 : Handle<FixedArray> GetForeignArgs() {
117 : Handle<FixedArray> ret = isolate_->factory()->NewFixedArray(
118 9651 : static_cast<int>(foreign_variables_.size()));
119 7034 : for (size_t i = 0; i < foreign_variables_.size(); ++i) {
120 : ForeignVariable* fv = &foreign_variables_[i];
121 900 : ret->set(static_cast<int>(i), *fv->name);
122 : }
123 3067 : return ret;
124 : }
125 :
126 6943 : bool Build() {
127 3532 : InitializeInitFunction();
128 3532 : if (!typer_->ValidateBeforeFunctionsPhase()) {
129 : return false;
130 : }
131 : DCHECK(!HasStackOverflow());
132 3411 : VisitFunctionLiteral(literal_);
133 3411 : if (HasStackOverflow()) {
134 : return false;
135 : }
136 3411 : if (!typer_finished_ && !typer_failed_) {
137 0 : typer_->FailWithMessage("Module missing export section.");
138 0 : typer_failed_ = true;
139 : }
140 3411 : if (typer_failed_) {
141 : return false;
142 : }
143 3067 : BuildForeignInitFunction();
144 3067 : init_function_->Emit(kExprEnd); // finish init function.
145 3067 : return true;
146 : }
147 :
148 : void VisitVariableDeclaration(VariableDeclaration* decl) {}
149 :
150 66660 : void VisitFunctionDeclaration(FunctionDeclaration* decl) {
151 : DCHECK_EQ(kModuleScope, scope_);
152 : DCHECK_NULL(current_function_builder_);
153 : FunctionLiteral* old_func = decl->fun();
154 : DeclarationScope* new_func_scope = nullptr;
155 : std::unique_ptr<ParseInfo> info;
156 11262 : if (decl->fun()->body() == nullptr) {
157 : // TODO(titzer/bradnelson): Reuse SharedFunctionInfos used here when
158 : // compiling the wasm module.
159 : Handle<SharedFunctionInfo> shared =
160 22524 : Compiler::GetSharedFunctionInfo(decl->fun(), script_, info_);
161 : shared->set_is_toplevel(false);
162 11262 : info.reset(new ParseInfo(script_));
163 : info->set_shared_info(shared);
164 : info->set_toplevel(false);
165 11262 : info->set_language_mode(decl->fun()->scope()->language_mode());
166 : info->set_allow_lazy_parsing(false);
167 : info->set_function_literal_id(shared->function_literal_id());
168 11262 : info->set_ast_value_factory(ast_value_factory_);
169 : info->set_ast_value_factory_owned(false);
170 : // Create fresh function scope to use to parse the function in.
171 : new_func_scope = new (info->zone()) DeclarationScope(
172 22524 : info->zone(), decl->fun()->scope()->outer_scope(), FUNCTION_SCOPE);
173 : info->set_asm_function_scope(new_func_scope);
174 22524 : if (!Compiler::ParseAndAnalyze(info.get(), info_->isolate())) {
175 6 : decl->fun()->scope()->outer_scope()->RemoveInnerScope(new_func_scope);
176 6 : if (isolate_->has_pending_exception()) {
177 6 : isolate_->clear_pending_exception();
178 : }
179 6 : typer_->TriggerParsingError();
180 6 : typer_failed_ = true;
181 : return;
182 : }
183 11256 : FunctionLiteral* func = info->literal();
184 : DCHECK_NOT_NULL(func);
185 : decl->set_fun(func);
186 : }
187 11256 : if (!typer_->ValidateInnerFunction(decl)) {
188 300 : typer_failed_ = true;
189 : decl->set_fun(old_func);
190 300 : if (new_func_scope != nullptr) {
191 : DCHECK_EQ(new_func_scope, decl->scope()->inner_scope());
192 22512 : if (!decl->scope()->RemoveInnerScope(new_func_scope)) {
193 0 : UNREACHABLE();
194 : }
195 : }
196 : return;
197 : }
198 10956 : current_function_builder_ = LookupOrInsertFunction(decl->proxy()->var());
199 10956 : scope_ = kFuncScope;
200 :
201 : // Record start of the function, used as position for the stack check.
202 : current_function_builder_->SetAsmFunctionStartPosition(
203 10956 : decl->fun()->start_position());
204 :
205 21912 : RECURSE(Visit(decl->fun()));
206 : decl->set_fun(old_func);
207 10956 : if (new_func_scope != nullptr) {
208 : DCHECK_EQ(new_func_scope, decl->scope()->inner_scope());
209 10956 : if (!decl->scope()->RemoveInnerScope(new_func_scope)) {
210 0 : UNREACHABLE();
211 : }
212 : }
213 10956 : scope_ = kModuleScope;
214 10956 : current_function_builder_ = nullptr;
215 : local_variables_.Clear();
216 10956 : typer_->ClearFunctionNodeTypes();
217 : }
218 :
219 484036 : void VisitStatements(ZoneList<Statement*>* stmts) {
220 968976 : for (int i = 0; i < stmts->length(); ++i) {
221 866433 : Statement* stmt = stmts->at(i);
222 634118 : ExpressionStatement* e = stmt->AsExpressionStatement();
223 634118 : if (e != nullptr && e->expression()->IsUndefinedLiteral()) {
224 : continue;
225 : }
226 865491 : RECURSE(Visit(stmt));
227 381455 : if (typer_failed_) break;
228 : }
229 : }
230 :
231 145693 : void VisitBlock(Block* stmt) {
232 85745 : if (stmt->statements()->length() == 1) {
233 32579 : ExpressionStatement* expr =
234 42691 : stmt->statements()->at(0)->AsExpressionStatement();
235 42691 : if (expr != nullptr) {
236 32579 : if (expr->expression()->IsAssignment()) {
237 : RECURSE(VisitExpressionStatement(expr));
238 : return;
239 : }
240 : }
241 : }
242 60074 : if (scope_ == kFuncScope) {
243 : BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock,
244 59948 : BreakTarget);
245 119896 : RECURSE(VisitStatements(stmt->statements()));
246 : } else {
247 126 : RECURSE(VisitStatements(stmt->statements()));
248 : }
249 : }
250 :
251 : class BlockVisitor {
252 : private:
253 : AsmWasmBuilderImpl* builder_;
254 :
255 : public:
256 157154 : BlockVisitor(AsmWasmBuilderImpl* builder, BreakableStatement* stmt,
257 : WasmOpcode opcode, TargetType target_type = NoTarget)
258 157154 : : builder_(builder) {
259 157154 : builder_->breakable_blocks_.emplace_back(stmt, target_type);
260 : // block and loops have a type immediate.
261 157154 : builder_->current_function_builder_->EmitWithU8(opcode, kLocalVoid);
262 157154 : }
263 157154 : ~BlockVisitor() {
264 157154 : builder_->current_function_builder_->Emit(kExprEnd);
265 157154 : builder_->breakable_blocks_.pop_back();
266 157154 : }
267 : };
268 :
269 277886 : void VisitExpressionStatement(ExpressionStatement* stmt) {
270 277886 : VisitForEffect(stmt->expression());
271 252215 : }
272 :
273 288761 : void VisitForEffect(Expression* expr) {
274 283664 : if (expr->IsAssignment()) {
275 : // Don't emit drops for assignments. Instead use SetLocal/GetLocal.
276 516542 : VisitAssignment(expr->AsAssignment(), kDrop);
277 258271 : return;
278 : }
279 25393 : if (expr->IsCall()) {
280 : // Only emit a drop if the call has a non-void return value.
281 32768 : if (VisitCallExpression(expr->AsCall()) && scope_ == kFuncScope) {
282 0 : current_function_builder_->Emit(kExprDrop);
283 : }
284 : return;
285 : }
286 9009 : if (expr->IsBinaryOperation()) {
287 15288 : BinaryOperation* binop = expr->AsBinaryOperation();
288 5688 : if (binop->op() == Token::COMMA) {
289 1956 : VisitForEffect(binop->left());
290 : VisitForEffect(binop->right());
291 1956 : return;
292 : }
293 : }
294 14106 : RECURSE(Visit(expr));
295 7053 : if (scope_ == kFuncScope) current_function_builder_->Emit(kExprDrop);
296 : }
297 :
298 : void VisitEmptyStatement(EmptyStatement* stmt) {}
299 :
300 0 : void VisitEmptyParentheses(EmptyParentheses* paren) { UNREACHABLE(); }
301 :
302 0 : void VisitGetIterator(GetIterator* expr) { UNREACHABLE(); }
303 :
304 0 : void VisitImportCallExpression(ImportCallExpression* expr) { UNREACHABLE(); }
305 :
306 194784 : void VisitIfStatement(IfStatement* stmt) {
307 : DCHECK_EQ(kFuncScope, scope_);
308 81332 : RECURSE(Visit(stmt->condition()));
309 : // Wasm ifs come with implicit blocks for both arms.
310 40666 : BlockVisitor block(this, nullptr, kExprIf);
311 40666 : if (stmt->HasThenStatement()) {
312 81308 : RECURSE(Visit(stmt->then_statement()));
313 : }
314 40666 : if (stmt->HasElseStatement()) {
315 16072 : current_function_builder_->Emit(kExprElse);
316 32144 : RECURSE(Visit(stmt->else_statement()));
317 40666 : }
318 : }
319 :
320 17152 : void DoBreakOrContinue(BreakableStatement* target, TargetType type) {
321 : DCHECK_EQ(kFuncScope, scope_);
322 580770 : for (int i = static_cast<int>(breakable_blocks_.size()) - 1; i >= 0; --i) {
323 1127236 : auto elem = breakable_blocks_.at(i);
324 563618 : if (elem.first == target && elem.second == type) {
325 17152 : int block_distance = static_cast<int>(breakable_blocks_.size() - i - 1);
326 17152 : current_function_builder_->EmitWithU32V(kExprBr, block_distance);
327 17152 : return;
328 : }
329 : }
330 0 : UNREACHABLE(); // statement not found
331 : }
332 :
333 876 : void VisitContinueStatement(ContinueStatement* stmt) {
334 876 : DoBreakOrContinue(stmt->target(), ContinueTarget);
335 : }
336 :
337 16276 : void VisitBreakStatement(BreakStatement* stmt) {
338 16276 : DoBreakOrContinue(stmt->target(), BreakTarget);
339 : }
340 :
341 126545 : void VisitReturnStatement(ReturnStatement* stmt) {
342 42207 : if (scope_ == kModuleScope) {
343 3105 : if (typer_finished_) {
344 0 : typer_->FailWithMessage("Module has multiple returns.");
345 0 : typer_failed_ = true;
346 0 : return;
347 : }
348 3105 : if (!typer_->ValidateAfterFunctionsPhase()) {
349 38 : typer_failed_ = true;
350 38 : return;
351 : }
352 3067 : typer_finished_ = true;
353 3067 : scope_ = kExportScope;
354 6134 : RECURSE(Visit(stmt->expression()));
355 3067 : scope_ = kModuleScope;
356 39102 : } else if (scope_ == kFuncScope) {
357 78204 : RECURSE(Visit(stmt->expression()));
358 39102 : current_function_builder_->Emit(kExprReturn);
359 : } else {
360 0 : UNREACHABLE();
361 : }
362 : }
363 :
364 0 : void VisitWithStatement(WithStatement* stmt) { UNREACHABLE(); }
365 :
366 9068 : void HandleCase(CaseNode* node,
367 : ZoneMap<int, unsigned int>& case_to_block,
368 : VariableProxy* tag, int default_block, int if_depth) {
369 : int prev_if_depth = if_depth;
370 9068 : if (node->left != nullptr) {
371 3336 : VisitVariableProxy(tag);
372 3336 : current_function_builder_->EmitI32Const(node->begin);
373 3336 : current_function_builder_->Emit(kExprI32LtS);
374 3336 : current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
375 3336 : if_depth++;
376 3336 : breakable_blocks_.emplace_back(nullptr, NoTarget);
377 3336 : HandleCase(node->left, case_to_block, tag, default_block, if_depth);
378 3336 : current_function_builder_->Emit(kExprElse);
379 : }
380 9068 : if (node->right != nullptr) {
381 5254 : VisitVariableProxy(tag);
382 5254 : current_function_builder_->EmitI32Const(node->end);
383 5254 : current_function_builder_->Emit(kExprI32GtS);
384 5254 : current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
385 5254 : if_depth++;
386 5254 : breakable_blocks_.emplace_back(nullptr, NoTarget);
387 5254 : HandleCase(node->right, case_to_block, tag, default_block, if_depth);
388 5254 : current_function_builder_->Emit(kExprElse);
389 : }
390 9068 : if (node->begin == node->end) {
391 8754 : VisitVariableProxy(tag);
392 8754 : current_function_builder_->EmitI32Const(node->begin);
393 8754 : current_function_builder_->Emit(kExprI32Eq);
394 8754 : current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
395 : DCHECK(case_to_block.find(node->begin) != case_to_block.end());
396 8754 : current_function_builder_->Emit(kExprBr);
397 : current_function_builder_->EmitU32V(1 + if_depth +
398 8754 : case_to_block[node->begin]);
399 8754 : current_function_builder_->Emit(kExprEnd);
400 : } else {
401 314 : if (node->begin != 0) {
402 226 : VisitVariableProxy(tag);
403 226 : current_function_builder_->EmitI32Const(node->begin);
404 226 : current_function_builder_->Emit(kExprI32Sub);
405 : } else {
406 88 : VisitVariableProxy(tag);
407 : }
408 314 : current_function_builder_->Emit(kExprBrTable);
409 314 : current_function_builder_->EmitU32V(node->end - node->begin + 1);
410 22258 : for (int v = node->begin; v <= node->end; ++v) {
411 21952 : if (case_to_block.find(v) != case_to_block.end()) {
412 19226 : uint32_t target = if_depth + case_to_block[v];
413 19226 : current_function_builder_->EmitU32V(target);
414 : } else {
415 2726 : uint32_t target = if_depth + default_block;
416 2726 : current_function_builder_->EmitU32V(target);
417 : }
418 21952 : if (v == kMaxInt) {
419 : break;
420 : }
421 : }
422 314 : uint32_t target = if_depth + default_block;
423 314 : current_function_builder_->EmitU32V(target);
424 : }
425 :
426 17658 : while (if_depth-- != prev_if_depth) {
427 : breakable_blocks_.pop_back();
428 8590 : current_function_builder_->Emit(kExprEnd);
429 : }
430 9068 : }
431 :
432 29426 : void VisitSwitchStatement(SwitchStatement* stmt) {
433 490 : VariableProxy* tag = stmt->tag()->AsVariableProxy();
434 : DCHECK_NOT_NULL(tag);
435 : ZoneList<CaseClause*>* clauses = stmt->cases();
436 490 : int case_count = clauses->length();
437 490 : if (case_count == 0) {
438 6 : return;
439 : }
440 : BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock,
441 484 : BreakTarget);
442 484 : ZoneVector<BlockVisitor*> blocks(zone_);
443 : ZoneVector<int32_t> cases(zone_);
444 : ZoneMap<int, unsigned int> case_to_block(zone_);
445 : bool has_default = false;
446 28930 : for (int i = case_count - 1; i >= 0; --i) {
447 56892 : CaseClause* clause = clauses->at(i);
448 56892 : blocks.push_back(new BlockVisitor(this, nullptr, kExprBlock));
449 28446 : if (!clause->is_default()) {
450 55960 : Literal* label = clause->label()->AsLiteral();
451 : Handle<Object> value = label->value();
452 : int32_t label_value;
453 27980 : bool label_is_i32 = value->ToInt32(&label_value);
454 : DCHECK(value->IsNumber() && label_is_i32);
455 : (void)label_is_i32;
456 27980 : case_to_block[label_value] = i;
457 27980 : cases.push_back(label_value);
458 : } else {
459 : DCHECK_EQ(i, case_count - 1);
460 : has_default = true;
461 : }
462 : }
463 484 : if (!has_default || case_count > 1) {
464 478 : int default_block = has_default ? case_count - 1 : case_count;
465 478 : BlockVisitor switch_logic_block(this, nullptr, kExprBlock);
466 478 : CaseNode* root = OrderCases(&cases, zone_);
467 478 : HandleCase(root, case_to_block, tag, default_block, 0);
468 630 : if (root->left != nullptr || root->right != nullptr ||
469 152 : root->begin == root->end) {
470 326 : current_function_builder_->Emit(kExprBr);
471 326 : current_function_builder_->EmitU32V(default_block);
472 478 : }
473 : }
474 28446 : for (int i = 0; i < case_count; ++i) {
475 28446 : CaseClause* clause = clauses->at(i);
476 56892 : RECURSE(VisitStatements(clause->statements()));
477 56892 : BlockVisitor* v = blocks.at(case_count - i - 1);
478 : blocks.pop_back();
479 28446 : delete v;
480 484 : }
481 : }
482 :
483 0 : void VisitCaseClause(CaseClause* clause) { UNREACHABLE(); }
484 :
485 21120 : void VisitDoWhileStatement(DoWhileStatement* stmt) {
486 : DCHECK_EQ(kFuncScope, scope_);
487 : BlockVisitor block(this, stmt->AsBreakableStatement(), kExprBlock,
488 5280 : BreakTarget);
489 10560 : BlockVisitor loop(this, stmt->AsBreakableStatement(), kExprLoop);
490 : {
491 : BlockVisitor inner_block(this, stmt->AsBreakableStatement(), kExprBlock,
492 5280 : ContinueTarget);
493 10560 : RECURSE(Visit(stmt->body()));
494 : }
495 10560 : RECURSE(Visit(stmt->cond()));
496 10560 : current_function_builder_->EmitWithU8(kExprBrIf, 0);
497 : }
498 :
499 14640 : void VisitWhileStatement(WhileStatement* stmt) {
500 : DCHECK_EQ(kFuncScope, scope_);
501 : BlockVisitor block(this, stmt->AsBreakableStatement(), kExprBlock,
502 3660 : BreakTarget);
503 : BlockVisitor loop(this, stmt->AsBreakableStatement(), kExprLoop,
504 7320 : ContinueTarget);
505 7320 : RECURSE(Visit(stmt->cond()));
506 7320 : BlockVisitor if_block(this, nullptr, kExprIf);
507 7320 : RECURSE(Visit(stmt->body()));
508 7320 : current_function_builder_->EmitWithU8(kExprBr, 1);
509 : }
510 :
511 1068 : void VisitForStatement(ForStatement* stmt) {
512 : DCHECK_EQ(kFuncScope, scope_);
513 156 : if (stmt->init() != nullptr) {
514 300 : RECURSE(Visit(stmt->init()));
515 : }
516 : BlockVisitor block(this, stmt->AsBreakableStatement(), kExprBlock,
517 156 : BreakTarget);
518 : BlockVisitor loop(this, stmt->AsBreakableStatement(), kExprLoop,
519 312 : ContinueTarget);
520 156 : if (stmt->cond() != nullptr) {
521 300 : RECURSE(Visit(stmt->cond()));
522 150 : current_function_builder_->Emit(kExprI32Eqz);
523 150 : current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
524 150 : current_function_builder_->EmitWithU8(kExprBr, 2);
525 150 : current_function_builder_->Emit(kExprEnd);
526 : }
527 156 : if (stmt->body() != nullptr) {
528 312 : RECURSE(Visit(stmt->body()));
529 : }
530 156 : if (stmt->next() != nullptr) {
531 288 : RECURSE(Visit(stmt->next()));
532 : }
533 312 : current_function_builder_->EmitWithU8(kExprBr, 0);
534 : }
535 :
536 0 : void VisitForInStatement(ForInStatement* stmt) { UNREACHABLE(); }
537 :
538 0 : void VisitForOfStatement(ForOfStatement* stmt) { UNREACHABLE(); }
539 :
540 0 : void VisitTryCatchStatement(TryCatchStatement* stmt) { UNREACHABLE(); }
541 :
542 0 : void VisitTryFinallyStatement(TryFinallyStatement* stmt) { UNREACHABLE(); }
543 :
544 0 : void VisitDebuggerStatement(DebuggerStatement* stmt) { UNREACHABLE(); }
545 :
546 85024 : void VisitFunctionLiteral(FunctionLiteral* expr) {
547 : DeclarationScope* scope = expr->scope();
548 14367 : if (scope_ == kFuncScope) {
549 21912 : if (auto* func_type = typer_->TypeOf(expr)->AsFunctionType()) {
550 : // Add the parameters for the function.
551 : const auto& arguments = func_type->Arguments();
552 56336 : for (int i = 0; i < expr->parameter_count(); ++i) {
553 34424 : ValueType type = TypeFrom(arguments[i]);
554 : DCHECK_NE(kWasmStmt, type);
555 34424 : InsertParameter(scope->parameter(i), type, i);
556 : }
557 : } else {
558 0 : UNREACHABLE();
559 : }
560 : }
561 28734 : RECURSE(VisitDeclarations(scope->declarations()));
562 14367 : if (typer_failed_) return;
563 28122 : RECURSE(VisitStatements(expr->body()));
564 14061 : if (scope_ == kFuncScope) {
565 : // Finish the function-body scope block.
566 10956 : current_function_builder_->Emit(kExprEnd);
567 : }
568 : }
569 :
570 0 : void VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
571 0 : UNREACHABLE();
572 : }
573 :
574 45654 : void VisitConditional(Conditional* expr) {
575 : DCHECK_EQ(kFuncScope, scope_);
576 13044 : RECURSE(Visit(expr->condition()));
577 : // Wasm ifs come with implicit blocks for both arms.
578 6522 : breakable_blocks_.emplace_back(nullptr, NoTarget);
579 : ValueTypeCode type;
580 6522 : switch (TypeOf(expr)) {
581 : case kWasmI32:
582 : type = kLocalI32;
583 : break;
584 : case kWasmI64:
585 : type = kLocalI64;
586 0 : break;
587 : case kWasmF32:
588 : type = kLocalF32;
589 0 : break;
590 : case kWasmF64:
591 : type = kLocalF64;
592 648 : break;
593 : default:
594 0 : UNREACHABLE();
595 : }
596 6522 : current_function_builder_->EmitWithU8(kExprIf, type);
597 13044 : RECURSE(Visit(expr->then_expression()));
598 6522 : current_function_builder_->Emit(kExprElse);
599 13044 : RECURSE(Visit(expr->else_expression()));
600 6522 : current_function_builder_->Emit(kExprEnd);
601 : breakable_blocks_.pop_back();
602 : }
603 :
604 388176 : bool VisitStdlibConstant(Variable* var) {
605 : AsmTyper::StandardMember standard_object =
606 388176 : typer_->VariableAsStandardMember(var);
607 : double value;
608 388176 : switch (standard_object) {
609 : case AsmTyper::kInfinity: {
610 : value = std::numeric_limits<double>::infinity();
611 : break;
612 : }
613 : case AsmTyper::kNaN: {
614 : value = std::numeric_limits<double>::quiet_NaN();
615 : break;
616 : }
617 : case AsmTyper::kMathE: {
618 : value = M_E;
619 : break;
620 : }
621 : case AsmTyper::kMathLN10: {
622 : value = M_LN10;
623 : break;
624 : }
625 : case AsmTyper::kMathLN2: {
626 : value = M_LN2;
627 : break;
628 : }
629 : case AsmTyper::kMathLOG10E: {
630 : value = M_LOG10E;
631 : break;
632 : }
633 : case AsmTyper::kMathLOG2E: {
634 : value = M_LOG2E;
635 : break;
636 : }
637 : case AsmTyper::kMathPI: {
638 : value = M_PI;
639 : break;
640 : }
641 : case AsmTyper::kMathSQRT1_2: {
642 : value = M_SQRT1_2;
643 : break;
644 : }
645 : case AsmTyper::kMathSQRT2: {
646 : value = M_SQRT2;
647 : break;
648 : }
649 : default: { return false; }
650 : }
651 60 : current_function_builder_->EmitF64Const(value);
652 : return true;
653 : }
654 :
655 1164646 : void VisitVariableProxy(VariableProxy* expr) {
656 388265 : if (scope_ == kFuncScope || scope_ == kInitScope) {
657 : Variable* var = expr->var();
658 388176 : if (VisitStdlibConstant(var)) {
659 388265 : return;
660 : }
661 : ValueType var_type = TypeOf(expr);
662 : DCHECK_NE(kWasmStmt, var_type);
663 388116 : if (var->IsContextSlot()) {
664 : current_function_builder_->EmitWithU32V(
665 8546 : kExprGetGlobal, LookupOrInsertGlobal(var, var_type));
666 : } else {
667 : current_function_builder_->EmitGetLocal(
668 379570 : LookupOrInsertLocal(var, var_type));
669 : }
670 89 : } else if (scope_ == kExportScope) {
671 : Variable* var = expr->var();
672 : DCHECK(var->is_function());
673 89 : WasmFunctionBuilder* function = LookupOrInsertFunction(var);
674 178 : function->ExportAs(CStrVector(AsmWasmBuilder::single_function_name));
675 : }
676 : }
677 :
678 311936 : void VisitLiteral(Literal* expr) {
679 : Handle<Object> value = expr->value();
680 310781 : if (!(value->IsNumber() || expr->raw_value()->IsTrue() ||
681 591556 : expr->raw_value()->IsFalse()) ||
682 288284 : (scope_ != kFuncScope && scope_ != kInitScope)) {
683 295775 : return;
684 : }
685 288284 : AsmType* type = typer_->TypeOf(expr);
686 : DCHECK_NE(type, AsmType::None());
687 :
688 288284 : if (type->IsA(AsmType::Signed())) {
689 279404 : int32_t i = 0;
690 279404 : CHECK(value->ToInt32(&i));
691 279404 : current_function_builder_->EmitI32Const(i);
692 8880 : } else if (type->IsA(AsmType::Unsigned()) || type->IsA(AsmType::FixNum())) {
693 222 : uint32_t u = 0;
694 222 : CHECK(value->ToUint32(&u));
695 222 : current_function_builder_->EmitI32Const(bit_cast<int32_t>(u));
696 8658 : } else if (type->IsA(AsmType::Int())) {
697 : // The parser can collapse !0, !1 etc to true / false.
698 : // Allow these as int literals.
699 56 : if (expr->raw_value()->IsTrue()) {
700 6 : current_function_builder_->EmitI32Const(1);
701 22 : } else if (expr->raw_value()->IsFalse()) {
702 6 : current_function_builder_->EmitI32Const(0);
703 16 : } else if (expr->raw_value()->IsNumber()) {
704 : // This can happen when -x becomes x * -1 (due to the parser).
705 16 : int32_t i = 0;
706 16 : CHECK(value->ToInt32(&i) && i == -1);
707 16 : current_function_builder_->EmitI32Const(-1);
708 : } else {
709 0 : UNREACHABLE();
710 : }
711 8630 : } else if (type->IsA(AsmType::Double())) {
712 : // TODO(bradnelson): Pattern match the case where negation occurs and
713 : // emit f64.neg instead.
714 8622 : double val = expr->raw_value()->AsNumber();
715 8622 : current_function_builder_->EmitF64Const(val);
716 8 : } else if (type->IsA(AsmType::Float())) {
717 : // This can happen when -fround(x) becomes fround(x) * 1.0[float]
718 : // (due to the parser).
719 : // TODO(bradnelson): Pattern match this and emit f32.neg instead.
720 8 : double val = expr->raw_value()->AsNumber();
721 : DCHECK_EQ(-1.0, val);
722 8 : current_function_builder_->EmitF32Const(val);
723 : } else {
724 0 : UNREACHABLE();
725 : }
726 : }
727 :
728 0 : void VisitRegExpLiteral(RegExpLiteral* expr) { UNREACHABLE(); }
729 :
730 2978 : void VisitObjectLiteral(ObjectLiteral* expr) {
731 : ZoneList<ObjectLiteralProperty*>* props = expr->properties();
732 14732 : for (int i = 0; i < props->length(); ++i) {
733 11754 : ObjectLiteralProperty* prop = props->at(i);
734 : DCHECK_EQ(kExportScope, scope_);
735 8776 : VariableProxy* expr = prop->value()->AsVariableProxy();
736 : DCHECK_NOT_NULL(expr);
737 : Variable* var = expr->var();
738 4388 : Literal* name = prop->key()->AsLiteral();
739 : DCHECK_NOT_NULL(name);
740 : DCHECK(name->IsPropertyName());
741 : Handle<String> function_name = name->AsPropertyName();
742 : int length;
743 : std::unique_ptr<char[]> utf8 = function_name->ToCString(
744 4388 : DISALLOW_NULLS, FAST_STRING_TRAVERSAL, &length);
745 4388 : if (var->is_function()) {
746 4388 : WasmFunctionBuilder* function = LookupOrInsertFunction(var);
747 8776 : function->ExportAs({utf8.get(), length});
748 : }
749 : }
750 2978 : }
751 :
752 0 : void VisitArrayLiteral(ArrayLiteral* expr) { UNREACHABLE(); }
753 :
754 : void LoadInitFunction() {
755 2522 : current_function_builder_ = init_function_;
756 2522 : scope_ = kInitScope;
757 : }
758 :
759 : void UnLoadInitFunction() {
760 2522 : scope_ = kModuleScope;
761 2522 : current_function_builder_ = nullptr;
762 : }
763 :
764 : struct FunctionTableIndices : public ZoneObject {
765 : uint32_t start_index;
766 : uint32_t signature_index;
767 : };
768 :
769 1344 : FunctionTableIndices* LookupOrAddFunctionTable(VariableProxy* table,
770 720 : Property* p) {
771 1164 : FunctionTableIndices* indices = LookupFunctionTable(table->var());
772 1164 : if (indices != nullptr) {
773 : // Already setup.
774 : return indices;
775 : }
776 180 : indices = new (zone()) FunctionTableIndices();
777 360 : auto* func_type = typer_->TypeOf(p)->AsFunctionType();
778 180 : auto* func_table_type = typer_->TypeOf(p->obj()->AsVariableProxy()->var())
779 360 : ->AsFunctionTableType();
780 : const auto& arguments = func_type->Arguments();
781 180 : ValueType return_type = TypeFrom(func_type->ReturnType());
782 : FunctionSig::Builder sig(zone(), return_type == kWasmStmt ? 0 : 1,
783 360 : arguments.size());
784 180 : if (return_type != kWasmStmt) {
785 : sig.AddReturn(return_type);
786 : }
787 738 : for (auto* arg : arguments) {
788 378 : sig.AddParam(TypeFrom(arg));
789 : }
790 180 : uint32_t signature_index = builder_->AddSignature(sig.Build());
791 : indices->start_index = builder_->AllocateIndirectFunctions(
792 180 : static_cast<uint32_t>(func_table_type->length()));
793 180 : indices->signature_index = signature_index;
794 : ZoneHashMap::Entry* entry = function_tables_.LookupOrInsert(
795 : table->var(), ComputePointerHash(table->var()),
796 360 : ZoneAllocationPolicy(zone()));
797 180 : entry->value = indices;
798 : return indices;
799 : }
800 :
801 1344 : FunctionTableIndices* LookupFunctionTable(Variable* v) {
802 : ZoneHashMap::Entry* entry =
803 1344 : function_tables_.Lookup(v, ComputePointerHash(v));
804 1344 : if (entry == nullptr) {
805 : return nullptr;
806 : }
807 1164 : return reinterpret_cast<FunctionTableIndices*>(entry->value);
808 : }
809 :
810 2916 : void PopulateFunctionTable(VariableProxy* table, ArrayLiteral* funcs) {
811 180 : FunctionTableIndices* indices = LookupFunctionTable(table->var());
812 : // Ignore unused function tables.
813 180 : if (indices == nullptr) {
814 180 : return;
815 : }
816 5292 : for (int i = 0; i < funcs->values()->length(); ++i) {
817 5112 : VariableProxy* func = funcs->values()->at(i)->AsVariableProxy();
818 : DCHECK_NOT_NULL(func);
819 : builder_->SetIndirectFunction(
820 : indices->start_index + i,
821 2556 : LookupOrInsertFunction(func->var())->func_index());
822 : }
823 : }
824 :
825 : class ImportedFunctionTable {
826 : private:
827 : class ImportedFunctionIndices : public ZoneObject {
828 : public:
829 : const char* name_;
830 : int name_length_;
831 : WasmModuleBuilder::SignatureMap signature_to_index_;
832 :
833 : ImportedFunctionIndices(const char* name, int name_length, Zone* zone)
834 2245 : : name_(name), name_length_(name_length), signature_to_index_(zone) {}
835 : };
836 : ZoneHashMap table_;
837 : AsmWasmBuilderImpl* builder_;
838 :
839 : public:
840 3532 : explicit ImportedFunctionTable(AsmWasmBuilderImpl* builder)
841 : : table_(ZoneHashMap::kDefaultHashMapCapacity,
842 : ZoneAllocationPolicy(builder->zone())),
843 3532 : builder_(builder) {}
844 :
845 9136 : ImportedFunctionIndices* LookupOrInsertImport(Variable* v) {
846 : auto* entry = table_.LookupOrInsert(
847 29653 : v, ComputePointerHash(v), ZoneAllocationPolicy(builder_->zone()));
848 : ImportedFunctionIndices* indices;
849 9136 : if (entry->value == nullptr) {
850 : indices = new (builder_->zone())
851 2245 : ImportedFunctionIndices(nullptr, 0, builder_->zone());
852 2245 : entry->value = indices;
853 : } else {
854 : indices = reinterpret_cast<ImportedFunctionIndices*>(entry->value);
855 : }
856 9136 : return indices;
857 : }
858 :
859 2245 : void SetImportName(Variable* v, const char* name, int name_length) {
860 2245 : auto* indices = LookupOrInsertImport(v);
861 2245 : indices->name_ = name;
862 2245 : indices->name_length_ = name_length;
863 5387 : for (auto i : indices->signature_to_index_) {
864 : builder_->builder_->SetImportName(i.second, indices->name_,
865 897 : indices->name_length_);
866 : }
867 2245 : }
868 :
869 : // Get a function's index (or allocate if new).
870 6891 : uint32_t LookupOrInsertImportUse(Variable* v, FunctionSig* sig) {
871 6891 : auto* indices = LookupOrInsertImport(v);
872 : WasmModuleBuilder::SignatureMap::iterator pos =
873 : indices->signature_to_index_.find(sig);
874 6891 : if (pos != indices->signature_to_index_.end()) {
875 5994 : return pos->second;
876 : } else {
877 : uint32_t index = builder_->builder_->AddImport(
878 897 : indices->name_, indices->name_length_, sig);
879 897 : indices->signature_to_index_[sig] = index;
880 897 : return index;
881 : }
882 : }
883 : };
884 :
885 245440 : void EmitAssignmentLhs(Expression* target, AsmType** atype) {
886 : // Match the left hand side of the assignment.
887 245440 : VariableProxy* target_var = target->AsVariableProxy();
888 245440 : if (target_var != nullptr) {
889 : // Left hand side is a local or a global variable, no code on LHS.
890 : return;
891 : }
892 :
893 : Property* target_prop = target->AsProperty();
894 51046 : if (target_prop != nullptr) {
895 : // Left hand side is a property access, i.e. the asm.js heap.
896 51046 : VisitPropertyAndEmitIndex(target_prop, atype);
897 51046 : return;
898 : }
899 :
900 0 : if (target_var == nullptr && target_prop == nullptr) {
901 0 : UNREACHABLE(); // invalid assignment.
902 : }
903 : }
904 :
905 245440 : void EmitAssignmentRhs(Expression* target, Expression* value, bool* is_nop) {
906 246340 : BinaryOperation* binop = value->AsBinaryOperation();
907 245440 : if (binop != nullptr) {
908 121234 : if (scope_ == kInitScope) {
909 : // Handle foreign variables in the initialization scope.
910 450 : Property* prop = binop->left()->AsProperty();
911 450 : if (binop->op() == Token::MUL) {
912 : DCHECK(binop->right()->IsLiteral());
913 : DCHECK_EQ(1.0, binop->right()->AsLiteral()->raw_value()->AsNumber());
914 : DCHECK(binop->right()->AsLiteral()->raw_value()->ContainsDot());
915 : DCHECK(target->IsVariableProxy());
916 264 : VisitForeignVariable(true, target->AsVariableProxy()->var(), prop);
917 132 : *is_nop = true;
918 132 : return;
919 318 : } else if (binop->op() == Token::BIT_OR) {
920 : DCHECK(binop->right()->IsLiteral());
921 : DCHECK_EQ(0.0, binop->right()->AsLiteral()->raw_value()->AsNumber());
922 : DCHECK(!binop->right()->AsLiteral()->raw_value()->ContainsDot());
923 : DCHECK(target->IsVariableProxy());
924 636 : VisitForeignVariable(false, target->AsVariableProxy()->var(), prop);
925 318 : *is_nop = true;
926 318 : return;
927 : } else {
928 0 : UNREACHABLE();
929 : }
930 : }
931 120784 : if (MatchBinaryOperation(binop) == kAsIs) {
932 111218 : VariableProxy* target_var = target->AsVariableProxy();
933 111218 : VariableProxy* effective_value_var = GetLeft(binop)->AsVariableProxy();
934 111218 : if (target_var != nullptr && effective_value_var != nullptr &&
935 : target_var->var() == effective_value_var->var()) {
936 16344 : *is_nop = true;
937 16344 : return;
938 : }
939 : }
940 : }
941 228646 : RECURSE(Visit(value));
942 : }
943 :
944 695154 : void EmitAssignment(Assignment* expr, AsmType* type, ValueFate fate) {
945 : // Match the left hand side of the assignment.
946 406246 : VariableProxy* target_var = expr->target()->AsVariableProxy();
947 228646 : if (target_var != nullptr) {
948 : // Left hand side is a local or a global variable.
949 : Variable* var = target_var->var();
950 : ValueType var_type = TypeOf(expr);
951 : DCHECK_NE(kWasmStmt, var_type);
952 177600 : if (var->IsContextSlot()) {
953 14634 : uint32_t index = LookupOrInsertGlobal(var, var_type);
954 14634 : current_function_builder_->EmitWithU32V(kExprSetGlobal, index);
955 14634 : if (fate == kLeaveOnStack) {
956 188 : current_function_builder_->EmitWithU32V(kExprGetGlobal, index);
957 : }
958 : } else {
959 162966 : if (fate == kDrop) {
960 : current_function_builder_->EmitSetLocal(
961 162846 : LookupOrInsertLocal(var, var_type));
962 : } else {
963 : current_function_builder_->EmitTeeLocal(
964 120 : LookupOrInsertLocal(var, var_type));
965 : }
966 : }
967 : }
968 :
969 228646 : Property* target_prop = expr->target()->AsProperty();
970 228646 : if (target_prop != nullptr) {
971 : // Left hand side is a property access, i.e. the asm.js heap.
972 60262 : if (TypeOf(expr->value()) == kWasmF64 && expr->target()->IsProperty() &&
973 9216 : typer_->TypeOf(expr->target()->AsProperty()->obj())
974 4608 : ->IsA(AsmType::Float32Array())) {
975 4170 : current_function_builder_->Emit(kExprF32ConvertF64);
976 : }
977 : // Note that unlike StoreMem, AsmjsStoreMem ignores out-of-bounds writes.
978 : WasmOpcode opcode;
979 51046 : if (type == AsmType::Int8Array()) {
980 : opcode = kExprI32AsmjsStoreMem8;
981 46030 : } else if (type == AsmType::Uint8Array()) {
982 : opcode = kExprI32AsmjsStoreMem8;
983 45962 : } else if (type == AsmType::Int16Array()) {
984 : opcode = kExprI32AsmjsStoreMem16;
985 44222 : } else if (type == AsmType::Uint16Array()) {
986 : opcode = kExprI32AsmjsStoreMem16;
987 44198 : } else if (type == AsmType::Int32Array()) {
988 : opcode = kExprI32AsmjsStoreMem;
989 4638 : } else if (type == AsmType::Uint32Array()) {
990 : opcode = kExprI32AsmjsStoreMem;
991 4614 : } else if (type == AsmType::Float32Array()) {
992 : opcode = kExprF32AsmjsStoreMem;
993 438 : } else if (type == AsmType::Float64Array()) {
994 : opcode = kExprF64AsmjsStoreMem;
995 : } else {
996 0 : UNREACHABLE();
997 : }
998 51046 : current_function_builder_->Emit(opcode);
999 51046 : if (fate == kDrop) {
1000 : // Asm.js stores to memory leave their result on the stack.
1001 50926 : current_function_builder_->Emit(kExprDrop);
1002 : }
1003 : }
1004 :
1005 228646 : if (target_var == nullptr && target_prop == nullptr) {
1006 0 : UNREACHABLE(); // invalid assignment.
1007 : }
1008 228646 : }
1009 :
1010 428 : void VisitAssignment(Assignment* expr) {
1011 428 : VisitAssignment(expr, kLeaveOnStack);
1012 428 : }
1013 :
1014 805091 : void VisitAssignment(Assignment* expr, ValueFate fate) {
1015 : bool as_init = false;
1016 258699 : if (scope_ == kModuleScope) {
1017 : // Skip extra assignment inserted by the parser when in this form:
1018 : // (function Module(a, b, c) {... })
1019 31562 : if (expr->target()->IsVariableProxy() &&
1020 31562 : expr->target()->AsVariableProxy()->var()->is_sloppy_function_name()) {
1021 13259 : return;
1022 : }
1023 25525 : Property* prop = expr->value()->AsProperty();
1024 13653 : if (prop != nullptr) {
1025 11952 : VariableProxy* vp = prop->obj()->AsVariableProxy();
1026 14277 : if (vp != nullptr && vp->var()->IsParameter() &&
1027 2325 : vp->var()->index() == 1) {
1028 4490 : VariableProxy* target = expr->target()->AsVariableProxy();
1029 4490 : if (typer_->TypeOf(target)->AsFFIType() != nullptr) {
1030 : const AstRawString* name =
1031 4490 : prop->key()->AsLiteral()->AsRawPropertyName();
1032 : imported_function_table_.SetImportName(
1033 : target->var(), reinterpret_cast<const char*>(name->raw_data()),
1034 2245 : name->length());
1035 : }
1036 : }
1037 : // Property values in module scope don't emit code, so return.
1038 : return;
1039 : }
1040 4026 : ArrayLiteral* funcs = expr->value()->AsArrayLiteral();
1041 4026 : if (funcs != nullptr) {
1042 180 : VariableProxy* target = expr->target()->AsVariableProxy();
1043 : DCHECK_NOT_NULL(target);
1044 180 : PopulateFunctionTable(target, funcs);
1045 : // Only add to the function table. No init needed.
1046 180 : return;
1047 : }
1048 3846 : if (expr->value()->IsCallNew()) {
1049 : // No init code to emit for CallNew nodes.
1050 : return;
1051 : }
1052 : as_init = true;
1053 : }
1054 :
1055 245440 : if (as_init) LoadInitFunction();
1056 245440 : AsmType* atype = AsmType::None();
1057 245440 : bool is_nop = false;
1058 245440 : EmitAssignmentLhs(expr->target(), &atype);
1059 245440 : EmitAssignmentRhs(expr->target(), expr->value(), &is_nop);
1060 245440 : if (!is_nop) {
1061 228646 : EmitAssignment(expr, atype, fate);
1062 : }
1063 245440 : if (as_init) UnLoadInitFunction();
1064 : }
1065 :
1066 0 : void VisitSuspend(Suspend* expr) { UNREACHABLE(); }
1067 :
1068 0 : void VisitThrow(Throw* expr) { UNREACHABLE(); }
1069 :
1070 450 : void VisitForeignVariable(bool is_float, Variable* var, Property* expr) {
1071 : DCHECK(expr->obj()->AsVariableProxy());
1072 : DCHECK(VariableLocation::PARAMETER ==
1073 : expr->obj()->AsVariableProxy()->var()->location());
1074 : DCHECK_EQ(1, expr->obj()->AsVariableProxy()->var()->index());
1075 900 : Literal* key_literal = expr->key()->AsLiteral();
1076 : DCHECK_NOT_NULL(key_literal);
1077 450 : if (!key_literal->value().is_null()) {
1078 : Handle<Name> name =
1079 900 : Object::ToName(isolate_, key_literal->value()).ToHandleChecked();
1080 450 : ValueType type = is_float ? kWasmF64 : kWasmI32;
1081 900 : foreign_variables_.push_back({name, var, type});
1082 : }
1083 450 : }
1084 :
1085 459580 : void VisitPropertyAndEmitIndex(Property* expr, AsmType** atype) {
1086 : Expression* obj = expr->obj();
1087 125898 : *atype = typer_->TypeOf(obj);
1088 125898 : int32_t size = (*atype)->ElementSizeInBytes();
1089 125898 : if (size == 1) {
1090 : // Allow more general expression in byte arrays than the spec
1091 : // strictly permits.
1092 : // Early versions of Emscripten emit HEAP8[HEAP32[..]|0] in
1093 : // places that strictly should be HEAP8[HEAP32[..]>>0].
1094 13122 : RECURSE(Visit(expr->key()));
1095 : return;
1096 : }
1097 :
1098 121660 : Literal* value = expr->key()->AsLiteral();
1099 112776 : if (value) {
1100 : DCHECK(value->raw_value()->IsNumber());
1101 : DCHECK_EQ(kWasmI32, TypeOf(value));
1102 8884 : int32_t val = static_cast<int32_t>(value->raw_value()->AsNumber());
1103 : // TODO(titzer): handle overflow here.
1104 8884 : current_function_builder_->EmitI32Const(val * size);
1105 8884 : return;
1106 : }
1107 207784 : BinaryOperation* binop = expr->key()->AsBinaryOperation();
1108 103892 : if (binop) {
1109 : DCHECK_EQ(Token::SAR, binop->op());
1110 : DCHECK(binop->right()->AsLiteral()->raw_value()->IsNumber());
1111 : DCHECK(kWasmI32 == TypeOf(binop->right()->AsLiteral()));
1112 : DCHECK_EQ(size,
1113 : 1 << static_cast<int>(
1114 : binop->right()->AsLiteral()->raw_value()->AsNumber()));
1115 : // Mask bottom bits to match asm.js behavior.
1116 207784 : RECURSE(Visit(binop->left()));
1117 103892 : current_function_builder_->EmitI32Const(~(size - 1));
1118 103892 : current_function_builder_->Emit(kExprI32And);
1119 103892 : return;
1120 : }
1121 0 : UNREACHABLE();
1122 : }
1123 :
1124 74852 : void VisitProperty(Property* expr) {
1125 74852 : AsmType* type = AsmType::None();
1126 74852 : VisitPropertyAndEmitIndex(expr, &type);
1127 : WasmOpcode opcode;
1128 74852 : if (type == AsmType::Int8Array()) {
1129 : opcode = kExprI32AsmjsLoadMem8S;
1130 69752 : } else if (type == AsmType::Uint8Array()) {
1131 : opcode = kExprI32AsmjsLoadMem8U;
1132 66814 : } else if (type == AsmType::Int16Array()) {
1133 : opcode = kExprI32AsmjsLoadMem16S;
1134 65794 : } else if (type == AsmType::Uint16Array()) {
1135 : opcode = kExprI32AsmjsLoadMem16U;
1136 65134 : } else if (type == AsmType::Int32Array()) {
1137 : opcode = kExprI32AsmjsLoadMem;
1138 7548 : } else if (type == AsmType::Uint32Array()) {
1139 : opcode = kExprI32AsmjsLoadMem;
1140 7518 : } else if (type == AsmType::Float32Array()) {
1141 : opcode = kExprF32AsmjsLoadMem;
1142 450 : } else if (type == AsmType::Float64Array()) {
1143 : opcode = kExprF64AsmjsLoadMem;
1144 : } else {
1145 0 : UNREACHABLE();
1146 : }
1147 :
1148 74852 : current_function_builder_->Emit(opcode);
1149 74852 : }
1150 :
1151 65238 : bool VisitStdlibFunction(Call* call, VariableProxy* expr) {
1152 : Variable* var = expr->var();
1153 : AsmTyper::StandardMember standard_object =
1154 32584 : typer_->VariableAsStandardMember(var);
1155 : ZoneList<Expression*>* args = call->arguments();
1156 : ValueType call_type = TypeOf(call);
1157 :
1158 32584 : switch (standard_object) {
1159 : case AsmTyper::kNone: {
1160 : return false;
1161 : }
1162 : case AsmTyper::kMathAcos: {
1163 26 : VisitCallArgs(call);
1164 : DCHECK_EQ(kWasmF64, call_type);
1165 26 : current_function_builder_->Emit(kExprF64Acos);
1166 26 : break;
1167 : }
1168 : case AsmTyper::kMathAsin: {
1169 26 : VisitCallArgs(call);
1170 : DCHECK_EQ(kWasmF64, call_type);
1171 26 : current_function_builder_->Emit(kExprF64Asin);
1172 26 : break;
1173 : }
1174 : case AsmTyper::kMathAtan: {
1175 26 : VisitCallArgs(call);
1176 : DCHECK_EQ(kWasmF64, call_type);
1177 26 : current_function_builder_->Emit(kExprF64Atan);
1178 26 : break;
1179 : }
1180 : case AsmTyper::kMathCos: {
1181 176 : VisitCallArgs(call);
1182 : DCHECK_EQ(kWasmF64, call_type);
1183 176 : current_function_builder_->Emit(kExprF64Cos);
1184 176 : break;
1185 : }
1186 : case AsmTyper::kMathSin: {
1187 176 : VisitCallArgs(call);
1188 : DCHECK_EQ(kWasmF64, call_type);
1189 176 : current_function_builder_->Emit(kExprF64Sin);
1190 176 : break;
1191 : }
1192 : case AsmTyper::kMathTan: {
1193 26 : VisitCallArgs(call);
1194 : DCHECK_EQ(kWasmF64, call_type);
1195 26 : current_function_builder_->Emit(kExprF64Tan);
1196 26 : break;
1197 : }
1198 : case AsmTyper::kMathExp: {
1199 26 : VisitCallArgs(call);
1200 : DCHECK_EQ(kWasmF64, call_type);
1201 26 : current_function_builder_->Emit(kExprF64Exp);
1202 26 : break;
1203 : }
1204 : case AsmTyper::kMathLog: {
1205 38 : VisitCallArgs(call);
1206 : DCHECK_EQ(kWasmF64, call_type);
1207 38 : current_function_builder_->Emit(kExprF64Log);
1208 38 : break;
1209 : }
1210 : case AsmTyper::kMathCeil: {
1211 46 : VisitCallArgs(call);
1212 46 : if (call_type == kWasmF32) {
1213 20 : current_function_builder_->Emit(kExprF32Ceil);
1214 26 : } else if (call_type == kWasmF64) {
1215 26 : current_function_builder_->Emit(kExprF64Ceil);
1216 : } else {
1217 0 : UNREACHABLE();
1218 : }
1219 : break;
1220 : }
1221 : case AsmTyper::kMathFloor: {
1222 82 : VisitCallArgs(call);
1223 82 : if (call_type == kWasmF32) {
1224 20 : current_function_builder_->Emit(kExprF32Floor);
1225 62 : } else if (call_type == kWasmF64) {
1226 62 : current_function_builder_->Emit(kExprF64Floor);
1227 : } else {
1228 0 : UNREACHABLE();
1229 : }
1230 : break;
1231 : }
1232 : case AsmTyper::kMathSqrt: {
1233 162 : VisitCallArgs(call);
1234 162 : if (call_type == kWasmF32) {
1235 12 : current_function_builder_->Emit(kExprF32Sqrt);
1236 150 : } else if (call_type == kWasmF64) {
1237 150 : current_function_builder_->Emit(kExprF64Sqrt);
1238 : } else {
1239 0 : UNREACHABLE();
1240 : }
1241 : break;
1242 : }
1243 : case AsmTyper::kMathClz32: {
1244 6 : VisitCallArgs(call);
1245 : DCHECK(call_type == kWasmI32);
1246 6 : current_function_builder_->Emit(kExprI32Clz);
1247 6 : break;
1248 : }
1249 : case AsmTyper::kMathAbs: {
1250 58 : if (call_type == kWasmI32) {
1251 14 : WasmTemporary tmp(current_function_builder_, kWasmI32);
1252 :
1253 : // if set_local(tmp, x) < 0
1254 14 : Visit(call->arguments()->at(0));
1255 14 : current_function_builder_->EmitTeeLocal(tmp.index());
1256 14 : current_function_builder_->EmitI32Const(0);
1257 14 : current_function_builder_->Emit(kExprI32LtS);
1258 14 : current_function_builder_->EmitWithU8(kExprIf, kLocalI32);
1259 :
1260 : // then (0 - tmp)
1261 14 : current_function_builder_->EmitI32Const(0);
1262 14 : current_function_builder_->EmitGetLocal(tmp.index());
1263 14 : current_function_builder_->Emit(kExprI32Sub);
1264 :
1265 : // else tmp
1266 14 : current_function_builder_->Emit(kExprElse);
1267 14 : current_function_builder_->EmitGetLocal(tmp.index());
1268 : // end
1269 14 : current_function_builder_->Emit(kExprEnd);
1270 :
1271 44 : } else if (call_type == kWasmF32) {
1272 12 : VisitCallArgs(call);
1273 12 : current_function_builder_->Emit(kExprF32Abs);
1274 32 : } else if (call_type == kWasmF64) {
1275 32 : VisitCallArgs(call);
1276 32 : current_function_builder_->Emit(kExprF64Abs);
1277 : } else {
1278 0 : UNREACHABLE();
1279 : }
1280 : break;
1281 : }
1282 : case AsmTyper::kMathMin: {
1283 : // TODO(bradnelson): Change wasm to match Math.min in asm.js mode.
1284 38 : if (call_type == kWasmI32) {
1285 14 : WasmTemporary tmp_x(current_function_builder_, kWasmI32);
1286 14 : WasmTemporary tmp_y(current_function_builder_, kWasmI32);
1287 :
1288 : // if set_local(tmp_x, x) < set_local(tmp_y, y)
1289 14 : Visit(call->arguments()->at(0));
1290 14 : current_function_builder_->EmitTeeLocal(tmp_x.index());
1291 :
1292 14 : Visit(call->arguments()->at(1));
1293 14 : current_function_builder_->EmitTeeLocal(tmp_y.index());
1294 :
1295 14 : current_function_builder_->Emit(kExprI32LeS);
1296 14 : current_function_builder_->EmitWithU8(kExprIf, kLocalI32);
1297 :
1298 : // then tmp_x
1299 14 : current_function_builder_->EmitGetLocal(tmp_x.index());
1300 :
1301 : // else tmp_y
1302 14 : current_function_builder_->Emit(kExprElse);
1303 14 : current_function_builder_->EmitGetLocal(tmp_y.index());
1304 14 : current_function_builder_->Emit(kExprEnd);
1305 :
1306 24 : } else if (call_type == kWasmF32) {
1307 12 : VisitCallArgs(call);
1308 12 : current_function_builder_->Emit(kExprF32Min);
1309 12 : } else if (call_type == kWasmF64) {
1310 12 : VisitCallArgs(call);
1311 12 : current_function_builder_->Emit(kExprF64Min);
1312 : } else {
1313 0 : UNREACHABLE();
1314 : }
1315 : break;
1316 : }
1317 : case AsmTyper::kMathMax: {
1318 : // TODO(bradnelson): Change wasm to match Math.max in asm.js mode.
1319 38 : if (call_type == kWasmI32) {
1320 14 : WasmTemporary tmp_x(current_function_builder_, kWasmI32);
1321 14 : WasmTemporary tmp_y(current_function_builder_, kWasmI32);
1322 :
1323 : // if set_local(tmp_x, x) < set_local(tmp_y, y)
1324 14 : Visit(call->arguments()->at(0));
1325 :
1326 14 : current_function_builder_->EmitTeeLocal(tmp_x.index());
1327 :
1328 14 : Visit(call->arguments()->at(1));
1329 14 : current_function_builder_->EmitTeeLocal(tmp_y.index());
1330 :
1331 14 : current_function_builder_->Emit(kExprI32LeS);
1332 14 : current_function_builder_->EmitWithU8(kExprIf, kLocalI32);
1333 :
1334 : // then tmp_y
1335 14 : current_function_builder_->EmitGetLocal(tmp_y.index());
1336 :
1337 : // else tmp_x
1338 14 : current_function_builder_->Emit(kExprElse);
1339 14 : current_function_builder_->EmitGetLocal(tmp_x.index());
1340 14 : current_function_builder_->Emit(kExprEnd);
1341 :
1342 24 : } else if (call_type == kWasmF32) {
1343 12 : VisitCallArgs(call);
1344 12 : current_function_builder_->Emit(kExprF32Max);
1345 12 : } else if (call_type == kWasmF64) {
1346 12 : VisitCallArgs(call);
1347 12 : current_function_builder_->Emit(kExprF64Max);
1348 : } else {
1349 0 : UNREACHABLE();
1350 : }
1351 : break;
1352 : }
1353 : case AsmTyper::kMathAtan2: {
1354 32 : VisitCallArgs(call);
1355 : DCHECK_EQ(kWasmF64, call_type);
1356 32 : current_function_builder_->Emit(kExprF64Atan2);
1357 32 : break;
1358 : }
1359 : case AsmTyper::kMathPow: {
1360 24 : VisitCallArgs(call);
1361 : DCHECK_EQ(kWasmF64, call_type);
1362 24 : current_function_builder_->Emit(kExprF64Pow);
1363 24 : break;
1364 : }
1365 : case AsmTyper::kMathImul: {
1366 286 : VisitCallArgs(call);
1367 286 : current_function_builder_->Emit(kExprI32Mul);
1368 286 : break;
1369 : }
1370 : case AsmTyper::kMathFround: {
1371 : DCHECK(args->length() == 1);
1372 1634 : Literal* literal = args->at(0)->AsLiteral();
1373 1484 : if (literal != nullptr) {
1374 : // constant fold Math.fround(#const);
1375 150 : if (literal->raw_value()->IsNumber()) {
1376 150 : float val = static_cast<float>(literal->raw_value()->AsNumber());
1377 150 : current_function_builder_->EmitF32Const(val);
1378 150 : return true;
1379 : }
1380 : }
1381 1334 : VisitCallArgs(call);
1382 : static const bool kDontIgnoreSign = false;
1383 1334 : switch (TypeIndexOf(args->at(0), kDontIgnoreSign)) {
1384 : case kInt32:
1385 : case kFixnum:
1386 18 : current_function_builder_->Emit(kExprF32SConvertI32);
1387 18 : break;
1388 : case kUint32:
1389 12 : current_function_builder_->Emit(kExprF32UConvertI32);
1390 12 : break;
1391 : case kFloat32:
1392 : break;
1393 : case kFloat64:
1394 12 : current_function_builder_->Emit(kExprF32ConvertF64);
1395 12 : break;
1396 : default:
1397 0 : UNREACHABLE();
1398 : }
1399 : break;
1400 : }
1401 : default: {
1402 0 : UNREACHABLE();
1403 : break;
1404 : }
1405 : }
1406 : return true;
1407 : }
1408 :
1409 102408 : void VisitCallArgs(Call* expr) {
1410 : ZoneList<Expression*>* args = expr->arguments();
1411 204816 : for (int i = 0; i < args->length(); ++i) {
1412 171260 : Expression* arg = args->at(i);
1413 171260 : RECURSE(Visit(arg));
1414 : }
1415 : }
1416 :
1417 17364 : void VisitCall(Call* expr) { VisitCallExpression(expr); }
1418 :
1419 125315 : bool VisitCallExpression(Call* expr) {
1420 33748 : Call::CallType call_type = expr->GetCallType();
1421 : bool returns_value = true;
1422 :
1423 : // Save the parent now, it might be overwritten in VisitCallArgs.
1424 33748 : BinaryOperation* parent_binop = parent_binop_;
1425 :
1426 33748 : switch (call_type) {
1427 : case Call::OTHER_CALL: {
1428 32584 : VariableProxy* proxy = expr->expression()->AsVariableProxy();
1429 32584 : if (proxy != nullptr) {
1430 : DCHECK(kFuncScope == scope_ ||
1431 : typer_->VariableAsStandardMember(proxy->var()) ==
1432 : AsmTyper::kMathFround);
1433 32584 : if (VisitStdlibFunction(expr, proxy)) {
1434 : return true;
1435 : }
1436 : }
1437 : DCHECK(kFuncScope == scope_);
1438 59616 : VariableProxy* vp = expr->expression()->AsVariableProxy();
1439 : DCHECK_NOT_NULL(vp);
1440 59616 : if (typer_->TypeOf(vp)->AsFFIType() != nullptr) {
1441 : ValueType return_type = TypeOf(expr);
1442 : ZoneList<Expression*>* args = expr->arguments();
1443 : FunctionSig::Builder sig(zone(), return_type == kWasmStmt ? 0 : 1,
1444 21120 : args->length());
1445 6891 : if (return_type != kWasmStmt) {
1446 : sig.AddReturn(return_type);
1447 : } else {
1448 : returns_value = false;
1449 : }
1450 28458 : for (int i = 0; i < args->length(); ++i) {
1451 7338 : sig.AddParam(TypeOf(args->at(i)));
1452 : }
1453 : uint32_t index = imported_function_table_.LookupOrInsertImportUse(
1454 13782 : vp->var(), sig.Build());
1455 6891 : VisitCallArgs(expr);
1456 : // For non-void functions, we must know the parent node.
1457 : DCHECK_IMPLIES(returns_value, parent_binop != nullptr);
1458 : DCHECK_IMPLIES(returns_value, parent_binop->left() == expr ||
1459 : parent_binop->right() == expr);
1460 30972 : int pos = expr->position();
1461 6891 : int parent_pos = returns_value ? parent_binop->position() : pos;
1462 6891 : current_function_builder_->AddAsmWasmOffset(pos, parent_pos);
1463 6891 : current_function_builder_->Emit(kExprCallFunction);
1464 6891 : current_function_builder_->EmitU32V(index);
1465 : } else {
1466 68751 : WasmFunctionBuilder* function = LookupOrInsertFunction(vp->var());
1467 22917 : VisitCallArgs(expr);
1468 : current_function_builder_->AddAsmWasmOffset(expr->position(),
1469 22917 : expr->position());
1470 22917 : current_function_builder_->Emit(kExprCallFunction);
1471 : current_function_builder_->EmitDirectCallIndex(
1472 22917 : function->func_index());
1473 22917 : returns_value = function->signature()->return_count() > 0;
1474 : }
1475 : break;
1476 : }
1477 : case Call::KEYED_PROPERTY_CALL: {
1478 : DCHECK_EQ(kFuncScope, scope_);
1479 3492 : Property* p = expr->expression()->AsProperty();
1480 : DCHECK_NOT_NULL(p);
1481 1164 : VariableProxy* var = p->obj()->AsVariableProxy();
1482 : DCHECK_NOT_NULL(var);
1483 1164 : FunctionTableIndices* indices = LookupOrAddFunctionTable(var, p);
1484 1164 : Visit(p->key()); // TODO(titzer): should use RECURSE()
1485 :
1486 : // We have to use a temporary for the correct order of evaluation.
1487 1164 : current_function_builder_->EmitI32Const(indices->start_index);
1488 1164 : current_function_builder_->Emit(kExprI32Add);
1489 1164 : WasmTemporary tmp(current_function_builder_, kWasmI32);
1490 1164 : current_function_builder_->EmitSetLocal(tmp.index());
1491 :
1492 1164 : VisitCallArgs(expr);
1493 :
1494 1164 : current_function_builder_->EmitGetLocal(tmp.index());
1495 : current_function_builder_->AddAsmWasmOffset(expr->position(),
1496 1164 : expr->position());
1497 1164 : current_function_builder_->Emit(kExprCallIndirect);
1498 1164 : current_function_builder_->EmitU32V(indices->signature_index);
1499 1164 : current_function_builder_->EmitU32V(0); // table index
1500 : returns_value =
1501 2328 : builder_->GetSignature(indices->signature_index)->return_count() >
1502 1164 : 0;
1503 : break;
1504 : }
1505 : default:
1506 0 : UNREACHABLE();
1507 : }
1508 30972 : return returns_value;
1509 : }
1510 :
1511 0 : void VisitCallNew(CallNew* expr) { UNREACHABLE(); }
1512 :
1513 0 : void VisitCallRuntime(CallRuntime* expr) { UNREACHABLE(); }
1514 :
1515 40062 : void VisitUnaryOperation(UnaryOperation* expr) {
1516 40062 : RECURSE(Visit(expr->expression()));
1517 13354 : switch (expr->op()) {
1518 : case Token::NOT: {
1519 : DCHECK_EQ(kWasmI32, TypeOf(expr->expression()));
1520 13354 : current_function_builder_->Emit(kExprI32Eqz);
1521 13354 : break;
1522 : }
1523 : default:
1524 0 : UNREACHABLE();
1525 : }
1526 : }
1527 :
1528 0 : void VisitCountOperation(CountOperation* expr) { UNREACHABLE(); }
1529 :
1530 880470 : bool MatchIntBinaryOperation(BinaryOperation* expr, Token::Value op,
1531 288146 : int32_t val) {
1532 : DCHECK_NOT_NULL(expr->right());
1533 880470 : if (expr->op() == op && expr->right()->IsLiteral() &&
1534 : TypeOf(expr) == kWasmI32) {
1535 576292 : Literal* right = expr->right()->AsLiteral();
1536 576292 : if (right->raw_value()->IsNumber() &&
1537 288146 : static_cast<int32_t>(right->raw_value()->AsNumber()) == val) {
1538 : return true;
1539 : }
1540 : }
1541 : return false;
1542 : }
1543 :
1544 92264 : bool MatchDoubleBinaryOperation(BinaryOperation* expr, Token::Value op,
1545 26790 : double val) {
1546 : DCHECK_NOT_NULL(expr->right());
1547 96038 : if (expr->op() == op && expr->right()->IsLiteral() &&
1548 : TypeOf(expr) == kWasmF64) {
1549 46032 : Literal* right = expr->right()->AsLiteral();
1550 : DCHECK(right->raw_value()->IsNumber());
1551 23016 : if (right->raw_value()->AsNumber() == val) {
1552 : return true;
1553 : }
1554 : }
1555 : return false;
1556 : }
1557 :
1558 : enum ConvertOperation { kNone, kAsIs, kToInt, kToDouble };
1559 :
1560 533410 : ConvertOperation MatchOr(BinaryOperation* expr) {
1561 533410 : if (MatchIntBinaryOperation(expr, Token::BIT_OR, 0) &&
1562 : (TypeOf(expr->left()) == kWasmI32)) {
1563 : return kAsIs;
1564 : } else {
1565 10174 : return kNone;
1566 : }
1567 : }
1568 :
1569 37060 : ConvertOperation MatchShr(BinaryOperation* expr) {
1570 22036 : if (MatchIntBinaryOperation(expr, Token::SHR, 0)) {
1571 : // TODO(titzer): this probably needs to be kToUint
1572 15024 : return (TypeOf(expr->left()) == kWasmI32) ? kAsIs : kToInt;
1573 : } else {
1574 : return kNone;
1575 : }
1576 : }
1577 :
1578 3068 : ConvertOperation MatchXor(BinaryOperation* expr) {
1579 1986 : if (MatchIntBinaryOperation(expr, Token::BIT_XOR, 0xffffffff)) {
1580 : DCHECK_EQ(kWasmI32, TypeOf(expr->left()));
1581 : DCHECK_EQ(kWasmI32, TypeOf(expr->right()));
1582 1082 : BinaryOperation* op = expr->left()->AsBinaryOperation();
1583 950 : if (op != nullptr) {
1584 564 : if (MatchIntBinaryOperation(op, Token::BIT_XOR, 0xffffffff)) {
1585 : DCHECK_EQ(kWasmI32, TypeOf(op->right()));
1586 132 : if (TypeOf(op->left()) != kWasmI32) {
1587 : return kToInt;
1588 : } else {
1589 0 : return kAsIs;
1590 : }
1591 : }
1592 : }
1593 : }
1594 : return kNone;
1595 : }
1596 :
1597 55958 : ConvertOperation MatchMul(BinaryOperation* expr) {
1598 34624 : if (MatchDoubleBinaryOperation(expr, Token::MUL, 1.0)) {
1599 : DCHECK_EQ(kWasmF64, TypeOf(expr->right()));
1600 21334 : if (TypeOf(expr->left()) != kWasmF64) {
1601 : return kToDouble;
1602 : } else {
1603 9280 : return kAsIs;
1604 : }
1605 : } else {
1606 : return kNone;
1607 : }
1608 : }
1609 :
1610 506346 : ConvertOperation MatchBinaryOperation(BinaryOperation* expr) {
1611 506346 : switch (expr->op()) {
1612 : case Token::BIT_OR:
1613 271792 : return MatchOr(expr);
1614 : case Token::SHR:
1615 22036 : return MatchShr(expr);
1616 : case Token::BIT_XOR:
1617 1986 : return MatchXor(expr);
1618 : case Token::MUL:
1619 34624 : return MatchMul(expr);
1620 : default:
1621 : return kNone;
1622 : }
1623 : }
1624 :
1625 : // Work around Mul + Div being defined in PPC assembler.
1626 : #ifdef Mul
1627 : #undef Mul
1628 : #endif
1629 :
1630 : #define NON_SIGNED_BINOP(op) \
1631 : static WasmOpcode opcodes[] = { \
1632 : kExprI32##op, \
1633 : kExprI32##op, \
1634 : kExprF32##op, \
1635 : kExprF64##op \
1636 : }
1637 :
1638 : #define SIGNED_BINOP(op) \
1639 : static WasmOpcode opcodes[] = { \
1640 : kExprI32##op##S, \
1641 : kExprI32##op##U, \
1642 : kExprF32##op, \
1643 : kExprF64##op \
1644 : }
1645 :
1646 : #define NON_SIGNED_INT_BINOP(op) \
1647 : static WasmOpcode opcodes[] = { kExprI32##op, kExprI32##op }
1648 :
1649 : #define BINOP_CASE(token, op, V, ignore_sign) \
1650 : case token: { \
1651 : V(op); \
1652 : int type = TypeIndexOf(expr->left(), expr->right(), ignore_sign); \
1653 : current_function_builder_->Emit(opcodes[type]); \
1654 : break; \
1655 : }
1656 :
1657 572228 : Expression* GetLeft(BinaryOperation* expr) {
1658 286114 : if (expr->op() == Token::BIT_XOR) {
1659 384 : return expr->left()->AsBinaryOperation()->left();
1660 : } else {
1661 : return expr->left();
1662 : }
1663 : }
1664 :
1665 1703152 : void VisitBinaryOperation(BinaryOperation* expr) {
1666 385562 : ConvertOperation convertOperation = MatchBinaryOperation(expr);
1667 : static const bool kDontIgnoreSign = false;
1668 385562 : parent_binop_ = expr;
1669 385562 : if (convertOperation == kToDouble) {
1670 15312 : RECURSE(Visit(expr->left()));
1671 7656 : TypeIndex type = TypeIndexOf(expr->left(), kDontIgnoreSign);
1672 7656 : if (type == kInt32 || type == kFixnum) {
1673 388 : current_function_builder_->Emit(kExprF64SConvertI32);
1674 7268 : } else if (type == kUint32) {
1675 164 : current_function_builder_->Emit(kExprF64UConvertI32);
1676 7104 : } else if (type == kFloat32) {
1677 7104 : current_function_builder_->Emit(kExprF64ConvertF32);
1678 : } else {
1679 0 : UNREACHABLE();
1680 : }
1681 377906 : } else if (convertOperation == kToInt) {
1682 192 : RECURSE(Visit(GetLeft(expr)));
1683 96 : TypeIndex type = TypeIndexOf(GetLeft(expr), kDontIgnoreSign);
1684 96 : if (type == kFloat32) {
1685 12 : current_function_builder_->Emit(kExprI32AsmjsSConvertF32);
1686 84 : } else if (type == kFloat64) {
1687 84 : current_function_builder_->Emit(kExprI32AsmjsSConvertF64);
1688 : } else {
1689 0 : UNREACHABLE();
1690 : }
1691 377810 : } else if (convertOperation == kAsIs) {
1692 192078 : RECURSE(Visit(GetLeft(expr)));
1693 : } else {
1694 185732 : if (expr->op() == Token::COMMA) {
1695 3732 : RECURSE(VisitForEffect(expr->left()));
1696 1866 : RECURSE(Visit(expr->right()));
1697 : return;
1698 : }
1699 367732 : RECURSE(Visit(expr->left()));
1700 367732 : RECURSE(Visit(expr->right()));
1701 :
1702 183866 : switch (expr->op()) {
1703 116108 : BINOP_CASE(Token::ADD, Add, NON_SIGNED_BINOP, true);
1704 9026 : BINOP_CASE(Token::SUB, Sub, NON_SIGNED_BINOP, true);
1705 12126 : BINOP_CASE(Token::MUL, Mul, NON_SIGNED_BINOP, true);
1706 6790 : BINOP_CASE(Token::BIT_OR, Ior, NON_SIGNED_INT_BINOP, true);
1707 14152 : BINOP_CASE(Token::BIT_AND, And, NON_SIGNED_INT_BINOP, true);
1708 1482 : BINOP_CASE(Token::BIT_XOR, Xor, NON_SIGNED_INT_BINOP, true);
1709 15730 : BINOP_CASE(Token::SHL, Shl, NON_SIGNED_INT_BINOP, true);
1710 2280 : BINOP_CASE(Token::SAR, ShrS, NON_SIGNED_INT_BINOP, true);
1711 5146 : BINOP_CASE(Token::SHR, ShrU, NON_SIGNED_INT_BINOP, true);
1712 : case Token::DIV: {
1713 : static WasmOpcode opcodes[] = {kExprI32AsmjsDivS, kExprI32AsmjsDivU,
1714 : kExprF32Div, kExprF64Div};
1715 632 : int type = TypeIndexOf(expr->left(), expr->right(), false);
1716 632 : current_function_builder_->Emit(opcodes[type]);
1717 632 : break;
1718 : }
1719 : case Token::MOD: {
1720 394 : TypeIndex type = TypeIndexOf(expr->left(), expr->right(), false);
1721 394 : if (type == kInt32) {
1722 254 : current_function_builder_->Emit(kExprI32AsmjsRemS);
1723 140 : } else if (type == kUint32) {
1724 116 : current_function_builder_->Emit(kExprI32AsmjsRemU);
1725 24 : } else if (type == kFloat64) {
1726 24 : current_function_builder_->Emit(kExprF64Mod);
1727 24 : return;
1728 : } else {
1729 0 : UNREACHABLE();
1730 : }
1731 : break;
1732 : }
1733 : case Token::COMMA: {
1734 : break;
1735 : }
1736 : default:
1737 0 : UNREACHABLE();
1738 : }
1739 : }
1740 : }
1741 :
1742 302220 : void VisitCompareOperation(CompareOperation* expr) {
1743 100740 : RECURSE(Visit(expr->left()));
1744 100740 : RECURSE(Visit(expr->right()));
1745 50370 : switch (expr->op()) {
1746 31932 : BINOP_CASE(Token::EQ, Eq, NON_SIGNED_BINOP, false);
1747 9348 : BINOP_CASE(Token::LT, Lt, SIGNED_BINOP, false);
1748 1682 : BINOP_CASE(Token::LTE, Le, SIGNED_BINOP, false);
1749 6200 : BINOP_CASE(Token::GT, Gt, SIGNED_BINOP, false);
1750 1208 : BINOP_CASE(Token::GTE, Ge, SIGNED_BINOP, false);
1751 : default:
1752 0 : UNREACHABLE();
1753 : }
1754 : }
1755 :
1756 : #undef BINOP_CASE
1757 : #undef NON_SIGNED_INT_BINOP
1758 : #undef SIGNED_BINOP
1759 : #undef NON_SIGNED_BINOP
1760 :
1761 : enum TypeIndex {
1762 : kInt32 = 0,
1763 : kUint32 = 1,
1764 : kFloat32 = 2,
1765 : kFloat64 = 3,
1766 : kFixnum = 4
1767 : };
1768 :
1769 234236 : TypeIndex TypeIndexOf(Expression* left, Expression* right, bool ignore_sign) {
1770 234236 : TypeIndex left_index = TypeIndexOf(left, ignore_sign);
1771 234236 : TypeIndex right_index = TypeIndexOf(right, ignore_sign);
1772 234236 : if (left_index == kFixnum) {
1773 : left_index = right_index;
1774 : }
1775 234236 : if (right_index == kFixnum) {
1776 : right_index = left_index;
1777 : }
1778 234236 : if (left_index == kFixnum && right_index == kFixnum) {
1779 : left_index = kInt32;
1780 : right_index = kInt32;
1781 : }
1782 : if (left_index != right_index) {
1783 : DCHECK(ignore_sign && (left_index <= 1) && (right_index <= 1));
1784 : }
1785 234236 : return left_index;
1786 : }
1787 :
1788 477558 : TypeIndex TypeIndexOf(Expression* expr, bool ignore_sign) {
1789 477558 : AsmType* type = typer_->TypeOf(expr);
1790 477558 : if (type->IsA(AsmType::FixNum())) {
1791 : return kFixnum;
1792 : }
1793 :
1794 322984 : if (type->IsA(AsmType::Signed())) {
1795 : return kInt32;
1796 : }
1797 :
1798 227398 : if (type->IsA(AsmType::Unsigned())) {
1799 : return kUint32;
1800 : }
1801 :
1802 209248 : if (type->IsA(AsmType::Intish())) {
1803 : if (!ignore_sign) {
1804 : // TODO(jpp): log a warning and move on.
1805 : }
1806 : return kInt32;
1807 : }
1808 :
1809 46300 : if (type->IsA(AsmType::Floatish())) {
1810 : return kFloat32;
1811 : }
1812 :
1813 37596 : if (type->IsA(AsmType::DoubleQ())) {
1814 : return kFloat64;
1815 : }
1816 :
1817 0 : UNREACHABLE();
1818 : return kInt32;
1819 : }
1820 :
1821 : #undef CASE
1822 : #undef NON_SIGNED_INT
1823 : #undef SIGNED
1824 : #undef NON_SIGNED
1825 :
1826 0 : void VisitThisFunction(ThisFunction* expr) { UNREACHABLE(); }
1827 :
1828 69758 : void VisitDeclarations(Declaration::List* decls) {
1829 83819 : for (Declaration* decl : *decls) {
1830 110782 : RECURSE(Visit(decl));
1831 55391 : if (typer_failed_) {
1832 : return;
1833 : }
1834 : }
1835 : }
1836 :
1837 0 : void VisitClassLiteral(ClassLiteral* expr) { UNREACHABLE(); }
1838 :
1839 0 : void VisitSpread(Spread* expr) { UNREACHABLE(); }
1840 :
1841 0 : void VisitSuperPropertyReference(SuperPropertyReference* expr) {
1842 0 : UNREACHABLE();
1843 : }
1844 :
1845 0 : void VisitSuperCallReference(SuperCallReference* expr) { UNREACHABLE(); }
1846 :
1847 0 : void VisitSloppyBlockFunctionStatement(SloppyBlockFunctionStatement* expr) {
1848 0 : UNREACHABLE();
1849 : }
1850 :
1851 0 : void VisitDoExpression(DoExpression* expr) { UNREACHABLE(); }
1852 :
1853 0 : void VisitRewritableExpression(RewritableExpression* expr) { UNREACHABLE(); }
1854 :
1855 : struct IndexContainer : public ZoneObject {
1856 : uint32_t index;
1857 : };
1858 :
1859 606376 : uint32_t LookupOrInsertLocal(Variable* v, ValueType type) {
1860 : DCHECK_NOT_NULL(current_function_builder_);
1861 : ZoneHashMap::Entry* entry =
1862 542536 : local_variables_.Lookup(v, ComputePointerHash(v));
1863 542536 : if (entry == nullptr) {
1864 : uint32_t index;
1865 : DCHECK(!v->IsParameter());
1866 31920 : index = current_function_builder_->AddLocal(type);
1867 31920 : IndexContainer* container = new (zone()) IndexContainer();
1868 31920 : container->index = index;
1869 : entry = local_variables_.LookupOrInsert(v, ComputePointerHash(v),
1870 63840 : ZoneAllocationPolicy(zone()));
1871 31920 : entry->value = container;
1872 : }
1873 542536 : return (reinterpret_cast<IndexContainer*>(entry->value))->index;
1874 : }
1875 :
1876 51636 : void InsertParameter(Variable* v, ValueType type, uint32_t index) {
1877 : DCHECK(v->IsParameter());
1878 : DCHECK_NOT_NULL(current_function_builder_);
1879 : ZoneHashMap::Entry* entry =
1880 17212 : local_variables_.Lookup(v, ComputePointerHash(v));
1881 : DCHECK_NULL(entry);
1882 17212 : IndexContainer* container = new (zone()) IndexContainer();
1883 17212 : container->index = index;
1884 : entry = local_variables_.LookupOrInsert(v, ComputePointerHash(v),
1885 34424 : ZoneAllocationPolicy(zone()));
1886 17212 : entry->value = container;
1887 17212 : }
1888 :
1889 26610 : uint32_t LookupOrInsertGlobal(Variable* v, ValueType type) {
1890 : ZoneHashMap::Entry* entry =
1891 23630 : global_variables_.Lookup(v, ComputePointerHash(v));
1892 23630 : if (entry == nullptr) {
1893 1490 : uint32_t index = builder_->AddGlobal(type, 0);
1894 1490 : IndexContainer* container = new (zone()) IndexContainer();
1895 1490 : container->index = index;
1896 : entry = global_variables_.LookupOrInsert(v, ComputePointerHash(v),
1897 2980 : ZoneAllocationPolicy(zone()));
1898 1490 : entry->value = container;
1899 : }
1900 23630 : return (reinterpret_cast<IndexContainer*>(entry->value))->index;
1901 : }
1902 :
1903 73828 : WasmFunctionBuilder* LookupOrInsertFunction(Variable* v) {
1904 : DCHECK_NOT_NULL(builder_);
1905 40906 : ZoneHashMap::Entry* entry = functions_.Lookup(v, ComputePointerHash(v));
1906 40906 : if (entry == nullptr) {
1907 21948 : auto* func_type = typer_->TypeOf(v)->AsFunctionType();
1908 : DCHECK_NOT_NULL(func_type);
1909 : // Build the signature for the function.
1910 10974 : ValueType return_type = TypeFrom(func_type->ReturnType());
1911 : const auto& arguments = func_type->Arguments();
1912 : FunctionSig::Builder b(zone(), return_type == kWasmStmt ? 0 : 1,
1913 50134 : arguments.size());
1914 10974 : if (return_type != kWasmStmt) b.AddReturn(return_type);
1915 45398 : for (int i = 0; i < static_cast<int>(arguments.size()); ++i) {
1916 34424 : ValueType type = TypeFrom(arguments[i]);
1917 : DCHECK_NE(kWasmStmt, type);
1918 : b.AddParam(type);
1919 : }
1920 :
1921 10974 : WasmFunctionBuilder* function = builder_->AddFunction(b.Build());
1922 : entry = functions_.LookupOrInsert(v, ComputePointerHash(v),
1923 21948 : ZoneAllocationPolicy(zone()));
1924 : function->SetName(
1925 : {reinterpret_cast<const char*>(v->raw_name()->raw_data()),
1926 10974 : v->raw_name()->length()});
1927 10974 : entry->value = function;
1928 : }
1929 40906 : return (reinterpret_cast<WasmFunctionBuilder*>(entry->value));
1930 : }
1931 :
1932 1283141 : ValueType TypeOf(Expression* expr) { return TypeFrom(typer_->TypeOf(expr)); }
1933 :
1934 1329097 : ValueType TypeFrom(AsmType* type) {
1935 1329097 : if (type->IsA(AsmType::Intish())) {
1936 : return kWasmI32;
1937 : }
1938 :
1939 127771 : if (type->IsA(AsmType::Floatish())) {
1940 : return kWasmF32;
1941 : }
1942 :
1943 110551 : if (type->IsA(AsmType::DoubleQ())) {
1944 : return kWasmF64;
1945 : }
1946 :
1947 : return kWasmStmt;
1948 : }
1949 :
1950 : Zone* zone() { return zone_; }
1951 :
1952 : ZoneHashMap local_variables_;
1953 : ZoneHashMap functions_;
1954 : ZoneHashMap global_variables_;
1955 : AsmScope scope_;
1956 : WasmModuleBuilder* builder_;
1957 : WasmFunctionBuilder* current_function_builder_;
1958 : FunctionLiteral* literal_;
1959 : Isolate* isolate_;
1960 : Zone* zone_;
1961 : CompilationInfo* info_;
1962 : AstValueFactory* ast_value_factory_;
1963 : Handle<Script> script_;
1964 : AsmTyper* typer_;
1965 : bool typer_failed_;
1966 : bool typer_finished_;
1967 : ZoneVector<std::pair<BreakableStatement*, TargetType>> breakable_blocks_;
1968 : ZoneVector<ForeignVariable> foreign_variables_;
1969 : WasmFunctionBuilder* init_function_;
1970 : WasmFunctionBuilder* foreign_init_function_;
1971 : uint32_t next_table_index_;
1972 : ZoneHashMap function_tables_;
1973 : ImportedFunctionTable imported_function_table_;
1974 : // Remember the parent node for reporting the correct location for ToNumber
1975 : // conversions after calls.
1976 : BinaryOperation* parent_binop_;
1977 :
1978 6972659 : DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
1979 :
1980 : private:
1981 : DISALLOW_COPY_AND_ASSIGN(AsmWasmBuilderImpl);
1982 : };
1983 :
1984 709392 : AsmWasmBuilder::AsmWasmBuilder(CompilationInfo* info)
1985 : : info_(info),
1986 709392 : typer_(info->isolate(), info->zone(), info->script(), info->literal()) {}
1987 :
1988 : // TODO(aseemgarg): probably should take zone (to write wasm to) as input so
1989 : // that zone in constructor may be thrown away once wasm module is written.
1990 3532 : AsmWasmBuilder::Result AsmWasmBuilder::Run(Handle<FixedArray>* foreign_args) {
1991 : HistogramTimerScope asm_wasm_time_scope(
1992 14128 : info_->isolate()->counters()->asm_wasm_translation_time());
1993 :
1994 3532 : Zone* zone = info_->zone();
1995 : AsmWasmBuilderImpl impl(info_->isolate(), zone, info_,
1996 : info_->parse_info()->ast_value_factory(),
1997 10596 : info_->script(), info_->literal(), &typer_);
1998 3532 : bool success = impl.Build();
1999 3532 : if (!success) {
2000 465 : return {nullptr, nullptr, success};
2001 : }
2002 3067 : *foreign_args = impl.GetForeignArgs();
2003 : ZoneBuffer* module_buffer = new (zone) ZoneBuffer(zone);
2004 3067 : impl.builder_->WriteTo(*module_buffer);
2005 : ZoneBuffer* asm_offsets_buffer = new (zone) ZoneBuffer(zone);
2006 3067 : impl.builder_->WriteAsmJsOffsetTable(*asm_offsets_buffer);
2007 3067 : return {module_buffer, asm_offsets_buffer, success};
2008 : }
2009 :
2010 : const char* AsmWasmBuilder::foreign_init_name = "__foreign_init__";
2011 : const char* AsmWasmBuilder::single_function_name = "__single_function__";
2012 :
2013 : } // namespace wasm
2014 : } // namespace internal
2015 : } // namespace v8
|