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 #include "src/wasm/asm-wasm-builder.h" |
| 8 #include "src/wasm/wasm-macro-gen.h" |
| 9 #include "src/wasm/wasm-opcodes.h" |
| 10 |
| 11 #include "src/ast/ast.h" |
| 12 #include "src/ast/scopes.h" |
| 13 #include "src/codegen.h" |
| 14 #include "src/type-cache.h" |
| 15 |
| 16 namespace v8 { |
| 17 namespace internal { |
| 18 namespace wasm { |
| 19 |
| 20 #define RECURSE(call) \ |
| 21 do { \ |
| 22 DCHECK(!HasStackOverflow()); \ |
| 23 call; \ |
| 24 if (HasStackOverflow()) return; \ |
| 25 } while (false) |
| 26 |
| 27 |
| 28 class AsmWasmBuilderImpl : public AstVisitor { |
| 29 public: |
| 30 AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, FunctionLiteral* literal) |
| 31 : local_variables_(HashMap::PointersMatch, |
| 32 ZoneHashMap::kDefaultHashMapCapacity, |
| 33 ZoneAllocationPolicy(zone)), |
| 34 functions_(HashMap::PointersMatch, ZoneHashMap::kDefaultHashMapCapacity, |
| 35 ZoneAllocationPolicy(zone)), |
| 36 global_variables_(HashMap::PointersMatch, |
| 37 ZoneHashMap::kDefaultHashMapCapacity, |
| 38 ZoneAllocationPolicy(zone)), |
| 39 in_function_(false), |
| 40 is_set_op_(false), |
| 41 marking_exported(false), |
| 42 builder_(new (zone) WasmModuleBuilder(zone)), |
| 43 current_function_builder_(NULL), |
| 44 literal_(literal), |
| 45 isolate_(isolate), |
| 46 zone_(zone), |
| 47 cache_(TypeCache::Get()), |
| 48 breakable_blocks_(zone), |
| 49 block_size_(0) { |
| 50 InitializeAstVisitor(isolate); |
| 51 } |
| 52 |
| 53 void Compile() { RECURSE(VisitFunctionLiteral(literal_)); } |
| 54 |
| 55 void VisitVariableDeclaration(VariableDeclaration* decl) {} |
| 56 |
| 57 void VisitFunctionDeclaration(FunctionDeclaration* decl) { |
| 58 DCHECK(!in_function_); |
| 59 DCHECK(current_function_builder_ == NULL); |
| 60 uint16_t index = LookupOrInsertFunction(decl->proxy()->var()); |
| 61 current_function_builder_ = builder_->FunctionAt(index); |
| 62 in_function_ = true; |
| 63 RECURSE(Visit(decl->fun())); |
| 64 in_function_ = false; |
| 65 current_function_builder_ = NULL; |
| 66 local_variables_.Clear(); |
| 67 } |
| 68 |
| 69 void VisitImportDeclaration(ImportDeclaration* decl) {} |
| 70 |
| 71 void VisitExportDeclaration(ExportDeclaration* decl) {} |
| 72 |
| 73 void VisitStatements(ZoneList<Statement*>* stmts) { |
| 74 for (int i = 0; i < stmts->length(); ++i) { |
| 75 Statement* stmt = stmts->at(i); |
| 76 RECURSE(Visit(stmt)); |
| 77 if (stmt->IsJump()) break; |
| 78 } |
| 79 } |
| 80 |
| 81 void VisitBlock(Block* stmt) { |
| 82 if (in_function_) { |
| 83 breakable_blocks_.push_back( |
| 84 std::make_pair(stmt->AsBreakableStatement(), false)); |
| 85 current_function_builder_->Emit(kExprBlock); |
| 86 uint32_t index = current_function_builder_->EmitEditableImmediate(0); |
| 87 int prev_block_size = block_size_; |
| 88 block_size_ = static_cast<byte>(stmt->statements()->length()); |
| 89 RECURSE(VisitStatements(stmt->statements())); |
| 90 DCHECK(block_size_ >= 0); |
| 91 current_function_builder_->EditImmediate(index, block_size_); |
| 92 block_size_ = prev_block_size; |
| 93 breakable_blocks_.pop_back(); |
| 94 } else { |
| 95 RECURSE(VisitStatements(stmt->statements())); |
| 96 } |
| 97 } |
| 98 |
| 99 void VisitExpressionStatement(ExpressionStatement* stmt) { |
| 100 RECURSE(Visit(stmt->expression())); |
| 101 } |
| 102 |
| 103 void VisitEmptyStatement(EmptyStatement* stmt) {} |
| 104 |
| 105 void VisitEmptyParentheses(EmptyParentheses* paren) { UNREACHABLE(); } |
| 106 |
| 107 void VisitIfStatement(IfStatement* stmt) { |
| 108 DCHECK(in_function_); |
| 109 if (stmt->HasElseStatement()) { |
| 110 current_function_builder_->Emit(kExprIfElse); |
| 111 } else { |
| 112 current_function_builder_->Emit(kExprIf); |
| 113 } |
| 114 RECURSE(Visit(stmt->condition())); |
| 115 if (stmt->HasThenStatement()) { |
| 116 RECURSE(Visit(stmt->then_statement())); |
| 117 } else { |
| 118 current_function_builder_->Emit(kExprNop); |
| 119 } |
| 120 if (stmt->HasElseStatement()) { |
| 121 RECURSE(Visit(stmt->else_statement())); |
| 122 } |
| 123 } |
| 124 |
| 125 void VisitContinueStatement(ContinueStatement* stmt) { |
| 126 DCHECK(in_function_); |
| 127 int i = static_cast<int>(breakable_blocks_.size()) - 1; |
| 128 int block_distance = 0; |
| 129 for (; i >= 0; i--) { |
| 130 auto elem = breakable_blocks_.at(i); |
| 131 if (elem.first == stmt->target()) { |
| 132 DCHECK(elem.second); |
| 133 break; |
| 134 } else if (elem.second) { |
| 135 block_distance += 2; |
| 136 } else { |
| 137 block_distance += 1; |
| 138 } |
| 139 } |
| 140 DCHECK(i >= 0); |
| 141 current_function_builder_->EmitWithU8(kExprBr, block_distance); |
| 142 current_function_builder_->Emit(kExprNop); |
| 143 } |
| 144 |
| 145 void VisitBreakStatement(BreakStatement* stmt) { |
| 146 DCHECK(in_function_); |
| 147 int i = static_cast<int>(breakable_blocks_.size()) - 1; |
| 148 int block_distance = 0; |
| 149 for (; i >= 0; i--) { |
| 150 auto elem = breakable_blocks_.at(i); |
| 151 if (elem.first == stmt->target()) { |
| 152 if (elem.second) { |
| 153 block_distance++; |
| 154 } |
| 155 break; |
| 156 } else if (elem.second) { |
| 157 block_distance += 2; |
| 158 } else { |
| 159 block_distance += 1; |
| 160 } |
| 161 } |
| 162 DCHECK(i >= 0); |
| 163 current_function_builder_->EmitWithU8(kExprBr, block_distance); |
| 164 current_function_builder_->Emit(kExprNop); |
| 165 } |
| 166 |
| 167 void VisitReturnStatement(ReturnStatement* stmt) { |
| 168 if (in_function_) { |
| 169 current_function_builder_->Emit(kExprReturn); |
| 170 } else { |
| 171 marking_exported = true; |
| 172 } |
| 173 RECURSE(Visit(stmt->expression())); |
| 174 if (!in_function_) { |
| 175 marking_exported = false; |
| 176 } |
| 177 } |
| 178 |
| 179 void VisitWithStatement(WithStatement* stmt) { |
| 180 RECURSE(stmt->expression()); |
| 181 RECURSE(stmt->statement()); |
| 182 } |
| 183 |
| 184 void VisitSwitchStatement(SwitchStatement* stmt) { |
| 185 RECURSE(Visit(stmt->tag())); |
| 186 |
| 187 ZoneList<CaseClause*>* clauses = stmt->cases(); |
| 188 |
| 189 for (int i = 0; i < clauses->length(); ++i) { |
| 190 CaseClause* clause = clauses->at(i); |
| 191 if (!clause->is_default()) { |
| 192 Expression* label = clause->label(); |
| 193 RECURSE(Visit(label)); |
| 194 } |
| 195 ZoneList<Statement*>* stmts = clause->statements(); |
| 196 RECURSE(VisitStatements(stmts)); |
| 197 } |
| 198 } |
| 199 |
| 200 void VisitCaseClause(CaseClause* clause) { UNREACHABLE(); } |
| 201 |
| 202 void VisitDoWhileStatement(DoWhileStatement* stmt) { |
| 203 RECURSE(Visit(stmt->body())); |
| 204 RECURSE(Visit(stmt->cond())); |
| 205 } |
| 206 |
| 207 void VisitWhileStatement(WhileStatement* stmt) { |
| 208 DCHECK(in_function_); |
| 209 current_function_builder_->EmitWithU8(kExprLoop, 1); |
| 210 breakable_blocks_.push_back( |
| 211 std::make_pair(stmt->AsBreakableStatement(), true)); |
| 212 current_function_builder_->Emit(kExprIf); |
| 213 RECURSE(Visit(stmt->cond())); |
| 214 current_function_builder_->EmitWithU8(kExprBr, 0); |
| 215 RECURSE(Visit(stmt->body())); |
| 216 breakable_blocks_.pop_back(); |
| 217 } |
| 218 |
| 219 void VisitForStatement(ForStatement* stmt) { |
| 220 if (stmt->init() != NULL) { |
| 221 RECURSE(Visit(stmt->init())); |
| 222 } |
| 223 if (stmt->cond() != NULL) { |
| 224 RECURSE(Visit(stmt->cond())); |
| 225 } |
| 226 if (stmt->next() != NULL) { |
| 227 RECURSE(Visit(stmt->next())); |
| 228 } |
| 229 RECURSE(Visit(stmt->body())); |
| 230 } |
| 231 |
| 232 void VisitForInStatement(ForInStatement* stmt) { |
| 233 RECURSE(Visit(stmt->enumerable())); |
| 234 RECURSE(Visit(stmt->body())); |
| 235 } |
| 236 |
| 237 void VisitForOfStatement(ForOfStatement* stmt) { |
| 238 RECURSE(Visit(stmt->iterable())); |
| 239 RECURSE(Visit(stmt->body())); |
| 240 } |
| 241 |
| 242 void VisitTryCatchStatement(TryCatchStatement* stmt) { |
| 243 RECURSE(Visit(stmt->try_block())); |
| 244 RECURSE(Visit(stmt->catch_block())); |
| 245 } |
| 246 |
| 247 void VisitTryFinallyStatement(TryFinallyStatement* stmt) { |
| 248 RECURSE(Visit(stmt->try_block())); |
| 249 RECURSE(Visit(stmt->finally_block())); |
| 250 } |
| 251 |
| 252 void VisitDebuggerStatement(DebuggerStatement* stmt) {} |
| 253 |
| 254 void VisitFunctionLiteral(FunctionLiteral* expr) { |
| 255 Scope* scope = expr->scope(); |
| 256 if (in_function_) { |
| 257 if (expr->bounds().lower->IsFunction()) { |
| 258 Type::FunctionType* func_type = expr->bounds().lower->AsFunction(); |
| 259 LocalType return_type = TypeFrom(func_type->Result()); |
| 260 current_function_builder_->ReturnType(return_type); |
| 261 for (int i = 0; i < expr->parameter_count(); i++) { |
| 262 LocalType type = TypeFrom(func_type->Parameter(i)); |
| 263 DCHECK(type != kAstStmt); |
| 264 LookupOrInsertLocal(scope->parameter(i), type); |
| 265 } |
| 266 } else { |
| 267 UNREACHABLE(); |
| 268 } |
| 269 } |
| 270 RECURSE(VisitDeclarations(scope->declarations())); |
| 271 RECURSE(VisitStatements(expr->body())); |
| 272 } |
| 273 |
| 274 void VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {} |
| 275 |
| 276 void VisitConditional(Conditional* expr) { |
| 277 RECURSE(Visit(expr->condition())); |
| 278 RECURSE(Visit(expr->then_expression())); |
| 279 RECURSE(Visit(expr->else_expression())); |
| 280 } |
| 281 |
| 282 void VisitVariableProxy(VariableProxy* expr) { |
| 283 if (in_function_) { |
| 284 Variable* var = expr->var(); |
| 285 if (var->is_function()) { |
| 286 DCHECK(!is_set_op_); |
| 287 std::vector<uint8_t> index = |
| 288 UnsignedLEB128From(LookupOrInsertFunction(var)); |
| 289 current_function_builder_->EmitCode( |
| 290 index.data(), static_cast<uint32_t>(index.size())); |
| 291 } else { |
| 292 if (is_set_op_) { |
| 293 if (var->IsContextSlot()) { |
| 294 current_function_builder_->Emit(kExprStoreGlobal); |
| 295 } else { |
| 296 current_function_builder_->Emit(kExprSetLocal); |
| 297 } |
| 298 is_set_op_ = false; |
| 299 } else { |
| 300 if (var->IsContextSlot()) { |
| 301 current_function_builder_->Emit(kExprLoadGlobal); |
| 302 } else { |
| 303 current_function_builder_->Emit(kExprGetLocal); |
| 304 } |
| 305 } |
| 306 LocalType var_type = TypeOf(expr); |
| 307 DCHECK(var_type != kAstStmt); |
| 308 if (var->IsContextSlot()) { |
| 309 AddLeb128(LookupOrInsertGlobal(var, var_type), false); |
| 310 } else { |
| 311 AddLeb128(LookupOrInsertLocal(var, var_type), true); |
| 312 } |
| 313 } |
| 314 } else if (marking_exported) { |
| 315 Variable* var = expr->var(); |
| 316 if (var->is_function()) { |
| 317 uint16_t index = LookupOrInsertFunction(var); |
| 318 builder_->FunctionAt(index)->Exported(1); |
| 319 } |
| 320 } |
| 321 } |
| 322 |
| 323 void VisitLiteral(Literal* expr) { |
| 324 if (in_function_) { |
| 325 if (expr->raw_value()->IsNumber()) { |
| 326 LocalType type = TypeOf(expr); |
| 327 switch (type) { |
| 328 case kAstI32: { |
| 329 int val = static_cast<int>(expr->raw_value()->AsNumber()); |
| 330 byte code[] = {WASM_I32(val)}; |
| 331 current_function_builder_->EmitCode(code, sizeof(code)); |
| 332 break; |
| 333 } |
| 334 case kAstF32: { |
| 335 float val = static_cast<float>(expr->raw_value()->AsNumber()); |
| 336 byte code[] = {WASM_F32(val)}; |
| 337 current_function_builder_->EmitCode(code, sizeof(code)); |
| 338 break; |
| 339 } |
| 340 case kAstF64: { |
| 341 double val = static_cast<double>(expr->raw_value()->AsNumber()); |
| 342 byte code[] = {WASM_F64(val)}; |
| 343 current_function_builder_->EmitCode(code, sizeof(code)); |
| 344 break; |
| 345 } |
| 346 default: |
| 347 UNREACHABLE(); |
| 348 } |
| 349 } |
| 350 } |
| 351 } |
| 352 |
| 353 void VisitRegExpLiteral(RegExpLiteral* expr) {} |
| 354 |
| 355 void VisitObjectLiteral(ObjectLiteral* expr) { |
| 356 ZoneList<ObjectLiteralProperty*>* props = expr->properties(); |
| 357 for (int i = 0; i < props->length(); ++i) { |
| 358 ObjectLiteralProperty* prop = props->at(i); |
| 359 RECURSE(Visit(prop->value())); |
| 360 } |
| 361 } |
| 362 |
| 363 void VisitArrayLiteral(ArrayLiteral* expr) { |
| 364 ZoneList<Expression*>* values = expr->values(); |
| 365 for (int i = 0; i < values->length(); ++i) { |
| 366 Expression* value = values->at(i); |
| 367 RECURSE(Visit(value)); |
| 368 } |
| 369 } |
| 370 |
| 371 void VisitAssignment(Assignment* expr) { |
| 372 if (in_function_) { |
| 373 BinaryOperation* value_op = expr->value()->AsBinaryOperation(); |
| 374 if (value_op != NULL && MatchBinaryOperation(value_op) == kAsIs) { |
| 375 VariableProxy* target_var = expr->target()->AsVariableProxy(); |
| 376 VariableProxy* effective_value_var = |
| 377 GetLeft(value_op)->AsVariableProxy(); |
| 378 // TODO(aseemgarg): simplify block_size_ or replace with a kNop |
| 379 if (target_var != NULL && effective_value_var != NULL && |
| 380 target_var->var() == effective_value_var->var()) { |
| 381 block_size_--; |
| 382 return; |
| 383 } |
| 384 } |
| 385 is_set_op_ = true; |
| 386 RECURSE(Visit(expr->target())); |
| 387 DCHECK(!is_set_op_); |
| 388 RECURSE(Visit(expr->value())); |
| 389 } |
| 390 } |
| 391 |
| 392 void VisitYield(Yield* expr) { |
| 393 RECURSE(Visit(expr->generator_object())); |
| 394 RECURSE(Visit(expr->expression())); |
| 395 } |
| 396 |
| 397 void VisitThrow(Throw* expr) { RECURSE(Visit(expr->exception())); } |
| 398 |
| 399 void VisitProperty(Property* expr) { |
| 400 Expression* obj = expr->obj(); |
| 401 DCHECK(obj->bounds().lower == obj->bounds().upper); |
| 402 TypeImpl<ZoneTypeConfig>* type = obj->bounds().lower; |
| 403 MachineType mtype; |
| 404 int size; |
| 405 if (type->Is(cache_.kUint8Array)) { |
| 406 mtype = MachineType::Uint8(); |
| 407 size = 1; |
| 408 } else if (type->Is(cache_.kInt8Array)) { |
| 409 mtype = MachineType::Int8(); |
| 410 size = 1; |
| 411 } else if (type->Is(cache_.kUint16Array)) { |
| 412 mtype = MachineType::Uint16(); |
| 413 size = 2; |
| 414 } else if (type->Is(cache_.kInt16Array)) { |
| 415 mtype = MachineType::Int16(); |
| 416 size = 2; |
| 417 } else if (type->Is(cache_.kUint32Array)) { |
| 418 mtype = MachineType::Uint32(); |
| 419 size = 4; |
| 420 } else if (type->Is(cache_.kInt32Array)) { |
| 421 mtype = MachineType::Int32(); |
| 422 size = 4; |
| 423 } else if (type->Is(cache_.kUint32Array)) { |
| 424 mtype = MachineType::Uint32(); |
| 425 size = 4; |
| 426 } else if (type->Is(cache_.kFloat32Array)) { |
| 427 mtype = MachineType::Float32(); |
| 428 size = 4; |
| 429 } else if (type->Is(cache_.kFloat64Array)) { |
| 430 mtype = MachineType::Float64(); |
| 431 size = 8; |
| 432 } else { |
| 433 UNREACHABLE(); |
| 434 } |
| 435 current_function_builder_->EmitWithU8( |
| 436 WasmOpcodes::LoadStoreOpcodeOf(mtype, is_set_op_), |
| 437 WasmOpcodes::LoadStoreAccessOf(false)); |
| 438 is_set_op_ = false; |
| 439 Literal* value = expr->key()->AsLiteral(); |
| 440 if (value) { |
| 441 DCHECK(value->raw_value()->IsNumber()); |
| 442 DCHECK(kAstI32 == TypeOf(value)); |
| 443 int val = static_cast<int>(value->raw_value()->AsNumber()); |
| 444 byte code[] = {WASM_I32(val * size)}; |
| 445 current_function_builder_->EmitCode(code, sizeof(code)); |
| 446 return; |
| 447 } |
| 448 BinaryOperation* binop = expr->key()->AsBinaryOperation(); |
| 449 if (binop) { |
| 450 DCHECK(Token::SAR == binop->op()); |
| 451 DCHECK(binop->right()->AsLiteral()->raw_value()->IsNumber()); |
| 452 DCHECK(kAstI32 == TypeOf(binop->right()->AsLiteral())); |
| 453 DCHECK(size == |
| 454 1 << static_cast<int>( |
| 455 binop->right()->AsLiteral()->raw_value()->AsNumber())); |
| 456 // Mask bottom bits to match asm.js behavior. |
| 457 current_function_builder_->Emit(kExprI32And); |
| 458 byte code[] = {WASM_I8(~(size - 1))}; |
| 459 current_function_builder_->EmitCode(code, sizeof(code)); |
| 460 RECURSE(Visit(binop->left())); |
| 461 return; |
| 462 } |
| 463 UNREACHABLE(); |
| 464 } |
| 465 |
| 466 void VisitCall(Call* expr) { |
| 467 Call::CallType call_type = expr->GetCallType(isolate_); |
| 468 switch (call_type) { |
| 469 case Call::OTHER_CALL: { |
| 470 DCHECK(in_function_); |
| 471 current_function_builder_->Emit(kExprCallFunction); |
| 472 RECURSE(Visit(expr->expression())); |
| 473 ZoneList<Expression*>* args = expr->arguments(); |
| 474 for (int i = 0; i < args->length(); ++i) { |
| 475 Expression* arg = args->at(i); |
| 476 RECURSE(Visit(arg)); |
| 477 } |
| 478 break; |
| 479 } |
| 480 default: |
| 481 UNREACHABLE(); |
| 482 } |
| 483 } |
| 484 |
| 485 void VisitCallNew(CallNew* expr) { UNREACHABLE(); } |
| 486 |
| 487 void VisitCallRuntime(CallRuntime* expr) { UNREACHABLE(); } |
| 488 |
| 489 void VisitUnaryOperation(UnaryOperation* expr) { |
| 490 switch (expr->op()) { |
| 491 case Token::NOT: { |
| 492 DCHECK(TypeOf(expr->expression()) == kAstI32); |
| 493 current_function_builder_->Emit(kExprBoolNot); |
| 494 break; |
| 495 } |
| 496 default: |
| 497 UNREACHABLE(); |
| 498 } |
| 499 RECURSE(Visit(expr->expression())); |
| 500 } |
| 501 |
| 502 void VisitCountOperation(CountOperation* expr) { |
| 503 RECURSE(Visit(expr->expression())); |
| 504 } |
| 505 |
| 506 bool MatchIntBinaryOperation(BinaryOperation* expr, Token::Value op, |
| 507 int32_t val) { |
| 508 DCHECK(expr->right() != NULL); |
| 509 if (expr->op() == op && expr->right()->IsLiteral() && |
| 510 TypeOf(expr) == kAstI32) { |
| 511 Literal* right = expr->right()->AsLiteral(); |
| 512 DCHECK(right->raw_value()->IsNumber()); |
| 513 if (static_cast<int32_t>(right->raw_value()->AsNumber()) == val) { |
| 514 return true; |
| 515 } |
| 516 } |
| 517 return false; |
| 518 } |
| 519 |
| 520 bool MatchDoubleBinaryOperation(BinaryOperation* expr, Token::Value op, |
| 521 double val) { |
| 522 DCHECK(expr->right() != NULL); |
| 523 if (expr->op() == op && expr->right()->IsLiteral() && |
| 524 TypeOf(expr) == kAstF64) { |
| 525 Literal* right = expr->right()->AsLiteral(); |
| 526 DCHECK(right->raw_value()->IsNumber()); |
| 527 if (right->raw_value()->AsNumber() == val) { |
| 528 return true; |
| 529 } |
| 530 } |
| 531 return false; |
| 532 } |
| 533 |
| 534 enum ConvertOperation { kNone, kAsIs, kToInt, kToDouble }; |
| 535 |
| 536 ConvertOperation MatchOr(BinaryOperation* expr) { |
| 537 if (MatchIntBinaryOperation(expr, Token::BIT_OR, 0)) { |
| 538 DCHECK(TypeOf(expr->left()) == kAstI32); |
| 539 DCHECK(TypeOf(expr->right()) == kAstI32); |
| 540 return kAsIs; |
| 541 } else { |
| 542 return kNone; |
| 543 } |
| 544 } |
| 545 |
| 546 ConvertOperation MatchShr(BinaryOperation* expr) { |
| 547 if (MatchIntBinaryOperation(expr, Token::SHR, 0)) { |
| 548 DCHECK(TypeOf(expr->left()) == kAstI32); |
| 549 DCHECK(TypeOf(expr->right()) == kAstI32); |
| 550 return kAsIs; |
| 551 } else { |
| 552 return kNone; |
| 553 } |
| 554 } |
| 555 |
| 556 ConvertOperation MatchXor(BinaryOperation* expr) { |
| 557 if (MatchIntBinaryOperation(expr, Token::BIT_XOR, 0xffffffff)) { |
| 558 DCHECK(TypeOf(expr->left()) == kAstI32); |
| 559 DCHECK(TypeOf(expr->right()) == kAstI32); |
| 560 BinaryOperation* op = expr->left()->AsBinaryOperation(); |
| 561 if (op != NULL) { |
| 562 if (MatchIntBinaryOperation(op, Token::BIT_XOR, 0xffffffff)) { |
| 563 DCHECK(TypeOf(op->right()) == kAstI32); |
| 564 if (TypeOf(op->left()) != kAstI32) { |
| 565 return kToInt; |
| 566 } else { |
| 567 return kAsIs; |
| 568 } |
| 569 } |
| 570 } |
| 571 } |
| 572 return kNone; |
| 573 } |
| 574 |
| 575 ConvertOperation MatchMul(BinaryOperation* expr) { |
| 576 if (MatchDoubleBinaryOperation(expr, Token::MUL, 1.0)) { |
| 577 DCHECK(TypeOf(expr->right()) == kAstF64); |
| 578 if (TypeOf(expr->left()) != kAstF64) { |
| 579 return kToDouble; |
| 580 } else { |
| 581 return kAsIs; |
| 582 } |
| 583 } else { |
| 584 return kNone; |
| 585 } |
| 586 } |
| 587 |
| 588 ConvertOperation MatchBinaryOperation(BinaryOperation* expr) { |
| 589 switch (expr->op()) { |
| 590 case Token::BIT_OR: |
| 591 return MatchOr(expr); |
| 592 case Token::SHR: |
| 593 return MatchShr(expr); |
| 594 case Token::BIT_XOR: |
| 595 return MatchXor(expr); |
| 596 case Token::MUL: |
| 597 return MatchMul(expr); |
| 598 default: |
| 599 return kNone; |
| 600 } |
| 601 } |
| 602 |
| 603 #define NON_SIGNED_BINOP(op) \ |
| 604 static WasmOpcode opcodes[] = { \ |
| 605 kExprI32##op, \ |
| 606 kExprI32##op, \ |
| 607 kExprF32##op, \ |
| 608 kExprF64##op \ |
| 609 } |
| 610 |
| 611 #define SIGNED_BINOP(op) \ |
| 612 static WasmOpcode opcodes[] = { \ |
| 613 kExprI32##op##S, \ |
| 614 kExprI32##op##U, \ |
| 615 kExprF32##op, \ |
| 616 kExprF64##op \ |
| 617 } |
| 618 |
| 619 #define NON_SIGNED_INT_BINOP(op) \ |
| 620 static WasmOpcode opcodes[] = { kExprI32##op, kExprI32##op } |
| 621 |
| 622 #define BINOP_CASE(token, op, V, ignore_sign) \ |
| 623 case token: { \ |
| 624 V(op); \ |
| 625 int type = TypeIndexOf(expr->left(), expr->right(), ignore_sign); \ |
| 626 current_function_builder_->Emit(opcodes[type]); \ |
| 627 break; \ |
| 628 } |
| 629 |
| 630 Expression* GetLeft(BinaryOperation* expr) { |
| 631 if (expr->op() == Token::BIT_XOR) { |
| 632 return expr->left()->AsBinaryOperation()->left(); |
| 633 } else { |
| 634 return expr->left(); |
| 635 } |
| 636 } |
| 637 |
| 638 void VisitBinaryOperation(BinaryOperation* expr) { |
| 639 ConvertOperation convertOperation = MatchBinaryOperation(expr); |
| 640 if (convertOperation == kToDouble) { |
| 641 TypeIndex type = TypeIndexOf(expr->left()); |
| 642 if (type == kInt32 || type == kFixnum) { |
| 643 current_function_builder_->Emit(kExprF64SConvertI32); |
| 644 } else if (type == kUint32) { |
| 645 current_function_builder_->Emit(kExprF64UConvertI32); |
| 646 } else if (type == kFloat32) { |
| 647 current_function_builder_->Emit(kExprF64ConvertF32); |
| 648 } else { |
| 649 UNREACHABLE(); |
| 650 } |
| 651 RECURSE(Visit(expr->left())); |
| 652 } else if (convertOperation == kToInt) { |
| 653 TypeIndex type = TypeIndexOf(GetLeft(expr)); |
| 654 if (type == kFloat32) { |
| 655 current_function_builder_->Emit(kExprI32SConvertF32); |
| 656 } else if (type == kFloat64) { |
| 657 current_function_builder_->Emit(kExprI32SConvertF64); |
| 658 } else { |
| 659 UNREACHABLE(); |
| 660 } |
| 661 RECURSE(Visit(GetLeft(expr))); |
| 662 } else if (convertOperation == kAsIs) { |
| 663 RECURSE(Visit(GetLeft(expr))); |
| 664 } else { |
| 665 switch (expr->op()) { |
| 666 BINOP_CASE(Token::ADD, Add, NON_SIGNED_BINOP, true); |
| 667 BINOP_CASE(Token::SUB, Sub, NON_SIGNED_BINOP, true); |
| 668 BINOP_CASE(Token::MUL, Mul, NON_SIGNED_BINOP, true); |
| 669 BINOP_CASE(Token::DIV, Div, SIGNED_BINOP, false); |
| 670 BINOP_CASE(Token::BIT_OR, Ior, NON_SIGNED_INT_BINOP, true); |
| 671 BINOP_CASE(Token::BIT_XOR, Xor, NON_SIGNED_INT_BINOP, true); |
| 672 BINOP_CASE(Token::SHL, Shl, NON_SIGNED_INT_BINOP, true); |
| 673 BINOP_CASE(Token::SAR, ShrS, NON_SIGNED_INT_BINOP, true); |
| 674 BINOP_CASE(Token::SHR, ShrU, NON_SIGNED_INT_BINOP, true); |
| 675 case Token::MOD: { |
| 676 TypeIndex type = TypeIndexOf(expr->left(), expr->right(), false); |
| 677 if (type == kInt32) { |
| 678 current_function_builder_->Emit(kExprI32RemS); |
| 679 } else if (type == kUint32) { |
| 680 current_function_builder_->Emit(kExprI32RemU); |
| 681 } else if (type == kFloat64) { |
| 682 ModF64(expr); |
| 683 return; |
| 684 } else { |
| 685 UNREACHABLE(); |
| 686 } |
| 687 break; |
| 688 } |
| 689 default: |
| 690 UNREACHABLE(); |
| 691 } |
| 692 RECURSE(Visit(expr->left())); |
| 693 RECURSE(Visit(expr->right())); |
| 694 } |
| 695 } |
| 696 |
| 697 void ModF64(BinaryOperation* expr) { |
| 698 current_function_builder_->EmitWithU8(kExprBlock, 3); |
| 699 uint16_t index_0 = current_function_builder_->AddLocal(kAstF64); |
| 700 uint16_t index_1 = current_function_builder_->AddLocal(kAstF64); |
| 701 current_function_builder_->Emit(kExprSetLocal); |
| 702 AddLeb128(index_0, true); |
| 703 RECURSE(Visit(expr->left())); |
| 704 current_function_builder_->Emit(kExprSetLocal); |
| 705 AddLeb128(index_1, true); |
| 706 RECURSE(Visit(expr->right())); |
| 707 current_function_builder_->Emit(kExprF64Sub); |
| 708 current_function_builder_->Emit(kExprGetLocal); |
| 709 AddLeb128(index_0, true); |
| 710 current_function_builder_->Emit(kExprF64Mul); |
| 711 current_function_builder_->Emit(kExprGetLocal); |
| 712 AddLeb128(index_1, true); |
| 713 // Use trunc instead of two casts |
| 714 current_function_builder_->Emit(kExprF64SConvertI32); |
| 715 current_function_builder_->Emit(kExprI32SConvertF64); |
| 716 current_function_builder_->Emit(kExprF64Div); |
| 717 current_function_builder_->Emit(kExprGetLocal); |
| 718 AddLeb128(index_0, true); |
| 719 current_function_builder_->Emit(kExprGetLocal); |
| 720 AddLeb128(index_1, true); |
| 721 } |
| 722 |
| 723 void AddLeb128(uint32_t index, bool is_local) { |
| 724 std::vector<uint8_t> index_vec = UnsignedLEB128From(index); |
| 725 if (is_local) { |
| 726 uint32_t pos_of_index[1] = {0}; |
| 727 current_function_builder_->EmitCode( |
| 728 index_vec.data(), static_cast<uint32_t>(index_vec.size()), |
| 729 pos_of_index, 1); |
| 730 } else { |
| 731 current_function_builder_->EmitCode( |
| 732 index_vec.data(), static_cast<uint32_t>(index_vec.size())); |
| 733 } |
| 734 } |
| 735 |
| 736 void VisitCompareOperation(CompareOperation* expr) { |
| 737 switch (expr->op()) { |
| 738 BINOP_CASE(Token::EQ, Eq, NON_SIGNED_BINOP, false); |
| 739 BINOP_CASE(Token::LT, Lt, SIGNED_BINOP, false); |
| 740 BINOP_CASE(Token::LTE, Le, SIGNED_BINOP, false); |
| 741 BINOP_CASE(Token::GT, Gt, SIGNED_BINOP, false); |
| 742 BINOP_CASE(Token::GTE, Ge, SIGNED_BINOP, false); |
| 743 default: |
| 744 UNREACHABLE(); |
| 745 } |
| 746 RECURSE(Visit(expr->left())); |
| 747 RECURSE(Visit(expr->right())); |
| 748 } |
| 749 |
| 750 #undef BINOP_CASE |
| 751 #undef NON_SIGNED_INT_BINOP |
| 752 #undef SIGNED_BINOP |
| 753 #undef NON_SIGNED_BINOP |
| 754 |
| 755 enum TypeIndex { |
| 756 kInt32 = 0, |
| 757 kUint32 = 1, |
| 758 kFloat32 = 2, |
| 759 kFloat64 = 3, |
| 760 kFixnum = 4 |
| 761 }; |
| 762 |
| 763 TypeIndex TypeIndexOf(Expression* left, Expression* right, bool ignore_sign) { |
| 764 TypeIndex left_index = TypeIndexOf(left); |
| 765 TypeIndex right_index = TypeIndexOf(right); |
| 766 if (left_index == kFixnum) { |
| 767 left_index = right_index; |
| 768 } |
| 769 if (right_index == kFixnum) { |
| 770 right_index = left_index; |
| 771 } |
| 772 if (left_index == kFixnum && right_index == kFixnum) { |
| 773 left_index = kInt32; |
| 774 right_index = kInt32; |
| 775 } |
| 776 DCHECK((left_index == right_index) || |
| 777 (ignore_sign && (left_index <= 1) && (right_index <= 1))); |
| 778 return left_index; |
| 779 } |
| 780 |
| 781 TypeIndex TypeIndexOf(Expression* expr) { |
| 782 DCHECK(expr->bounds().lower == expr->bounds().upper); |
| 783 TypeImpl<ZoneTypeConfig>* type = expr->bounds().lower; |
| 784 if (type->Is(cache_.kAsmFixnum)) { |
| 785 return kFixnum; |
| 786 } else if (type->Is(cache_.kAsmSigned)) { |
| 787 return kInt32; |
| 788 } else if (type->Is(cache_.kAsmUnsigned)) { |
| 789 return kUint32; |
| 790 } else if (type->Is(cache_.kAsmInt)) { |
| 791 return kInt32; |
| 792 } else if (type->Is(cache_.kAsmFloat)) { |
| 793 return kFloat32; |
| 794 } else if (type->Is(cache_.kAsmDouble)) { |
| 795 return kFloat64; |
| 796 } else { |
| 797 UNREACHABLE(); |
| 798 } |
| 799 } |
| 800 |
| 801 #undef CASE |
| 802 #undef NON_SIGNED_INT |
| 803 #undef SIGNED |
| 804 #undef NON_SIGNED |
| 805 |
| 806 void VisitThisFunction(ThisFunction* expr) {} |
| 807 |
| 808 void VisitDeclarations(ZoneList<Declaration*>* decls) { |
| 809 for (int i = 0; i < decls->length(); ++i) { |
| 810 Declaration* decl = decls->at(i); |
| 811 RECURSE(Visit(decl)); |
| 812 } |
| 813 } |
| 814 |
| 815 void VisitClassLiteral(ClassLiteral* expr) {} |
| 816 |
| 817 void VisitSpread(Spread* expr) {} |
| 818 |
| 819 void VisitSuperPropertyReference(SuperPropertyReference* expr) {} |
| 820 |
| 821 void VisitSuperCallReference(SuperCallReference* expr) {} |
| 822 |
| 823 void VisitSloppyBlockFunctionStatement(SloppyBlockFunctionStatement* expr) {} |
| 824 |
| 825 void VisitDoExpression(DoExpression* expr) {} |
| 826 |
| 827 void VisitRewritableAssignmentExpression( |
| 828 RewritableAssignmentExpression* expr) {} |
| 829 |
| 830 struct IndexContainer : public ZoneObject { |
| 831 uint16_t index; |
| 832 }; |
| 833 |
| 834 uint16_t LookupOrInsertLocal(Variable* v, LocalType type) { |
| 835 DCHECK(current_function_builder_ != NULL); |
| 836 ZoneHashMap::Entry* entry = |
| 837 local_variables_.Lookup(v, ComputePointerHash(v)); |
| 838 if (entry == NULL) { |
| 839 uint16_t index; |
| 840 if (v->IsParameter()) { |
| 841 index = current_function_builder_->AddParam(type); |
| 842 } else { |
| 843 index = current_function_builder_->AddLocal(type); |
| 844 } |
| 845 IndexContainer* container = new (zone()) IndexContainer(); |
| 846 container->index = index; |
| 847 entry = local_variables_.LookupOrInsert(v, ComputePointerHash(v), |
| 848 ZoneAllocationPolicy(zone())); |
| 849 entry->value = container; |
| 850 } |
| 851 return (reinterpret_cast<IndexContainer*>(entry->value))->index; |
| 852 } |
| 853 |
| 854 uint16_t LookupOrInsertGlobal(Variable* v, LocalType type) { |
| 855 ZoneHashMap::Entry* entry = |
| 856 global_variables_.Lookup(v, ComputePointerHash(v)); |
| 857 if (entry == NULL) { |
| 858 uint16_t index = |
| 859 builder_->AddGlobal(WasmOpcodes::MachineTypeFor(type), 0); |
| 860 IndexContainer* container = new (zone()) IndexContainer(); |
| 861 container->index = index; |
| 862 entry = global_variables_.LookupOrInsert(v, ComputePointerHash(v), |
| 863 ZoneAllocationPolicy(zone())); |
| 864 entry->value = container; |
| 865 } |
| 866 return (reinterpret_cast<IndexContainer*>(entry->value))->index; |
| 867 } |
| 868 |
| 869 uint16_t LookupOrInsertFunction(Variable* v) { |
| 870 DCHECK(builder_ != NULL); |
| 871 ZoneHashMap::Entry* entry = functions_.Lookup(v, ComputePointerHash(v)); |
| 872 if (entry == NULL) { |
| 873 uint16_t index = builder_->AddFunction(v->raw_name()->raw_data(), |
| 874 v->raw_name()->length()); |
| 875 IndexContainer* container = new (zone()) IndexContainer(); |
| 876 container->index = index; |
| 877 entry = functions_.LookupOrInsert(v, ComputePointerHash(v), |
| 878 ZoneAllocationPolicy(zone())); |
| 879 entry->value = container; |
| 880 } |
| 881 return (reinterpret_cast<IndexContainer*>(entry->value))->index; |
| 882 } |
| 883 |
| 884 LocalType TypeOf(Expression* expr) { |
| 885 DCHECK(expr->bounds().lower == expr->bounds().upper); |
| 886 return TypeFrom(expr->bounds().lower); |
| 887 } |
| 888 |
| 889 LocalType TypeFrom(TypeImpl<ZoneTypeConfig>* type) { |
| 890 if (type->Is(cache_.kAsmInt)) { |
| 891 return kAstI32; |
| 892 } else if (type->Is(cache_.kAsmFloat)) { |
| 893 return kAstF32; |
| 894 } else if (type->Is(cache_.kAsmDouble)) { |
| 895 return kAstF64; |
| 896 } else { |
| 897 return kAstStmt; |
| 898 } |
| 899 } |
| 900 |
| 901 Zone* zone() { return zone_; } |
| 902 |
| 903 ZoneHashMap local_variables_; |
| 904 ZoneHashMap functions_; |
| 905 ZoneHashMap global_variables_; |
| 906 bool in_function_; |
| 907 bool is_set_op_; |
| 908 bool marking_exported; |
| 909 WasmModuleBuilder* builder_; |
| 910 WasmFunctionBuilder* current_function_builder_; |
| 911 FunctionLiteral* literal_; |
| 912 Isolate* isolate_; |
| 913 Zone* zone_; |
| 914 TypeCache const& cache_; |
| 915 ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_; |
| 916 int block_size_; |
| 917 |
| 918 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); |
| 919 |
| 920 private: |
| 921 DISALLOW_COPY_AND_ASSIGN(AsmWasmBuilderImpl); |
| 922 }; |
| 923 |
| 924 AsmWasmBuilder::AsmWasmBuilder(Isolate* isolate, Zone* zone, |
| 925 FunctionLiteral* literal) |
| 926 : isolate_(isolate), zone_(zone), literal_(literal) {} |
| 927 |
| 928 // TODO(aseemgarg): probably should take zone (to write wasm to) as input so |
| 929 // that zone in constructor may be thrown away once wasm module is written. |
| 930 WasmModuleIndex* AsmWasmBuilder::Run() { |
| 931 AsmWasmBuilderImpl impl(isolate_, zone_, literal_); |
| 932 impl.Compile(); |
| 933 WasmModuleWriter* writer = impl.builder_->Build(zone_); |
| 934 return writer->WriteTo(zone_); |
| 935 } |
| 936 } // namespace wasm |
| 937 } // namespace internal |
| 938 } // namespace v8 |
OLD | NEW |