github.com/kidsbmilk/gofronted_all@v0.0.0-20220701224323-6479d5976c5d/go/wb.cc (about) 1 // wb.cc -- Add write barriers as needed. 2 3 // Copyright 2017 The Go Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file. 6 7 #include "go-system.h" 8 9 #include "go-c.h" 10 #include "go-diagnostics.h" 11 #include "operator.h" 12 #include "lex.h" 13 #include "types.h" 14 #include "expressions.h" 15 #include "statements.h" 16 #include "runtime.h" 17 #include "gogo.h" 18 19 // Mark variables whose addresses are taken and do some other 20 // cleanups. This has to be done before the write barrier pass and 21 // after the escape analysis pass. It would be nice to do this 22 // elsewhere but there isn't an obvious place. 23 24 class Mark_address_taken : public Traverse 25 { 26 public: 27 Mark_address_taken(Gogo* gogo) 28 : Traverse(traverse_functions 29 | traverse_statements 30 | traverse_expressions), 31 gogo_(gogo), function_(NULL) 32 { } 33 34 int 35 function(Named_object*); 36 37 int 38 statement(Block*, size_t*, Statement*); 39 40 int 41 expression(Expression**); 42 43 private: 44 // General IR. 45 Gogo* gogo_; 46 // The function we are traversing. 47 Named_object* function_; 48 }; 49 50 // Record a function. 51 52 int 53 Mark_address_taken::function(Named_object* no) 54 { 55 go_assert(this->function_ == NULL); 56 this->function_ = no; 57 int t = no->func_value()->traverse(this); 58 this->function_ = NULL; 59 60 if (t == TRAVERSE_EXIT) 61 return t; 62 return TRAVERSE_SKIP_COMPONENTS; 63 } 64 65 // Traverse a statement. 66 67 int 68 Mark_address_taken::statement(Block* block, size_t* pindex, Statement* s) 69 { 70 // If this is an assignment of the form s = append(s, ...), expand 71 // it now, so that we can assign it to the left hand side in the 72 // middle of the expansion and possibly skip a write barrier. 73 Assignment_statement* as = s->assignment_statement(); 74 if (as != NULL && !as->lhs()->is_sink_expression()) 75 { 76 Call_expression* rce = as->rhs()->call_expression(); 77 if (rce != NULL 78 && rce->builtin_call_expression() != NULL 79 && (rce->builtin_call_expression()->code() 80 == Builtin_call_expression::BUILTIN_APPEND) 81 && Expression::is_same_variable(as->lhs(), rce->args()->front())) 82 { 83 Statement_inserter inserter = Statement_inserter(block, pindex); 84 Expression* a = 85 rce->builtin_call_expression()->flatten_append(this->gogo_, 86 this->function_, 87 &inserter, 88 as->lhs(), 89 block); 90 go_assert(a == NULL); 91 // That does the assignment, so remove this statement. 92 Expression* e = Expression::make_boolean(true, s->location()); 93 Statement* dummy = Statement::make_statement(e, true); 94 block->replace_statement(*pindex, dummy); 95 } 96 } 97 return TRAVERSE_CONTINUE; 98 } 99 100 // Mark variable addresses taken. 101 102 int 103 Mark_address_taken::expression(Expression** pexpr) 104 { 105 Expression* expr = *pexpr; 106 Unary_expression* ue = expr->unary_expression(); 107 if (ue != NULL) 108 ue->check_operand_address_taken(this->gogo_); 109 110 Array_index_expression* aie = expr->array_index_expression(); 111 if (aie != NULL 112 && aie->end() != NULL 113 && !aie->array()->type()->is_slice_type()) 114 { 115 // Slice of an array. The escape analysis models this with 116 // a child Node representing the address of the array. 117 bool escapes = false; 118 Node* n = Node::make_node(expr); 119 if (n->child() == NULL 120 || (n->child()->encoding() & ESCAPE_MASK) != Node::ESCAPE_NONE) 121 escapes = true; 122 aie->array()->address_taken(escapes); 123 } 124 125 if (expr->allocation_expression() != NULL) 126 { 127 Node* n = Node::make_node(expr); 128 if ((n->encoding() & ESCAPE_MASK) == Node::ESCAPE_NONE) 129 expr->allocation_expression()->set_allocate_on_stack(); 130 } 131 if (expr->heap_expression() != NULL) 132 { 133 Node* n = Node::make_node(expr); 134 if ((n->encoding() & ESCAPE_MASK) == Node::ESCAPE_NONE) 135 expr->heap_expression()->set_allocate_on_stack(); 136 } 137 if (expr->slice_literal() != NULL) 138 { 139 Node* n = Node::make_node(expr); 140 if ((n->encoding() & ESCAPE_MASK) == Node::ESCAPE_NONE) 141 expr->slice_literal()->set_storage_does_not_escape(); 142 } 143 144 // Rewrite non-escaping makeslice with constant size to stack allocation. 145 Slice_value_expression* sve = expr->slice_value_expression(); 146 if (sve != NULL) 147 { 148 std::pair<Call_expression*, Temporary_statement*> p = 149 Expression::find_makeslice_call(sve); 150 Call_expression* call = p.first; 151 Temporary_statement* ts = p.second; 152 if (call != NULL 153 && Node::make_node(call)->encoding() == Node::ESCAPE_NONE) 154 { 155 Expression* len_arg = call->args()->at(1); 156 Expression* cap_arg = call->args()->at(2); 157 Numeric_constant nclen; 158 Numeric_constant nccap; 159 unsigned long vlen; 160 unsigned long vcap; 161 if (len_arg->numeric_constant_value(&nclen) 162 && cap_arg->numeric_constant_value(&nccap) 163 && nclen.to_unsigned_long(&vlen) == Numeric_constant::NC_UL_VALID 164 && nccap.to_unsigned_long(&vcap) == Numeric_constant::NC_UL_VALID) 165 { 166 // Stack allocate an array and make a slice value from it. 167 Location loc = expr->location(); 168 Type* elmt_type = expr->type()->array_type()->element_type(); 169 Expression* len_expr = 170 Expression::make_integer_ul(vcap, cap_arg->type(), loc); 171 Type* array_type = Type::make_array_type(elmt_type, len_expr); 172 Expression* alloc = Expression::make_allocation(array_type, loc); 173 alloc->allocation_expression()->set_allocate_on_stack(); 174 Type* ptr_type = Type::make_pointer_type(elmt_type); 175 Expression* ptr = Expression::make_unsafe_cast(ptr_type, alloc, 176 loc); 177 Expression* slice = 178 Expression::make_slice_value(expr->type(), ptr, len_arg, 179 cap_arg, loc); 180 *pexpr = slice; 181 if (ts != NULL && ts->uses() == 1) 182 ts->set_init(Expression::make_nil(loc)); 183 } 184 } 185 } 186 return TRAVERSE_CONTINUE; 187 } 188 189 // Check variables and closures do not escape when compiling runtime. 190 191 class Check_escape : public Traverse 192 { 193 public: 194 Check_escape(Gogo* gogo) 195 : Traverse(traverse_expressions | traverse_variables), 196 gogo_(gogo) 197 { } 198 199 int 200 expression(Expression**); 201 202 int 203 variable(Named_object*); 204 205 private: 206 Gogo* gogo_; 207 }; 208 209 int 210 Check_escape::variable(Named_object* no) 211 { 212 if ((no->is_variable() && no->var_value()->is_in_heap()) 213 || (no->is_result_variable() 214 && no->result_var_value()->is_in_heap())) 215 go_error_at(no->location(), 216 "%s escapes to heap, not allowed in runtime", 217 no->message_name().c_str()); 218 return TRAVERSE_CONTINUE; 219 } 220 221 int 222 Check_escape::expression(Expression** pexpr) 223 { 224 Expression* expr = *pexpr; 225 Func_expression* fe = expr->func_expression(); 226 if (fe != NULL && fe->closure() != NULL) 227 { 228 Node* n = Node::make_node(expr); 229 if (n->encoding() == Node::ESCAPE_HEAP) 230 go_error_at(expr->location(), 231 "heap-allocated closure, not allowed in runtime"); 232 } 233 return TRAVERSE_CONTINUE; 234 } 235 236 // Collect all writebarrierrec functions. This is used when compiling 237 // the runtime package, to propagate //go:nowritebarrierrec. 238 239 class Collect_writebarrierrec_functions : public Traverse 240 { 241 public: 242 Collect_writebarrierrec_functions(std::vector<Named_object*>* worklist) 243 : Traverse(traverse_functions), 244 worklist_(worklist) 245 { } 246 247 private: 248 int 249 function(Named_object*); 250 251 // The collected functions are put here. 252 std::vector<Named_object*>* worklist_; 253 }; 254 255 int 256 Collect_writebarrierrec_functions::function(Named_object* no) 257 { 258 if (no->is_function() 259 && no->func_value()->enclosing() == NULL 260 && (no->func_value()->pragmas() & GOPRAGMA_NOWRITEBARRIERREC) != 0) 261 { 262 go_assert((no->func_value()->pragmas() & GOPRAGMA_MARK) == 0); 263 this->worklist_->push_back(no); 264 } 265 return TRAVERSE_CONTINUE; 266 } 267 268 // Collect all callees of this function. We only care about locally 269 // defined, known, functions. 270 271 class Collect_callees : public Traverse 272 { 273 public: 274 Collect_callees(std::vector<Named_object*>* worklist) 275 : Traverse(traverse_expressions), 276 worklist_(worklist) 277 { } 278 279 private: 280 int 281 expression(Expression**); 282 283 // The collected callees are put here. 284 std::vector<Named_object*>* worklist_; 285 }; 286 287 int 288 Collect_callees::expression(Expression** pexpr) 289 { 290 Call_expression* ce = (*pexpr)->call_expression(); 291 if (ce != NULL) 292 { 293 Func_expression* fe = ce->fn()->func_expression(); 294 if (fe != NULL) 295 { 296 Named_object* no = fe->named_object(); 297 if (no->package() == NULL && no->is_function()) 298 { 299 // The function runtime.systemstack is special, in that 300 // it is a common way to call a function in the runtime: 301 // mark its argument if we can. 302 if (Gogo::unpack_hidden_name(no->name()) != "systemstack") 303 this->worklist_->push_back(no); 304 else if (ce->args()->size() > 0) 305 { 306 fe = ce->args()->front()->func_expression(); 307 if (fe != NULL) 308 { 309 no = fe->named_object(); 310 if (no->package() == NULL && no->is_function()) 311 this->worklist_->push_back(no); 312 } 313 } 314 } 315 } 316 } 317 return TRAVERSE_CONTINUE; 318 } 319 320 // When compiling the runtime package, propagate //go:nowritebarrierrec 321 // annotations. A function marked as //go:nowritebarrierrec does not 322 // permit write barriers, and also all the functions that it calls, 323 // recursively, do not permit write barriers. Except that a 324 // //go:yeswritebarrierrec annotation permits write barriers even if 325 // called by a //go:nowritebarrierrec function. Here we turn 326 // //go:nowritebarrierrec into //go:nowritebarrier, as appropriate. 327 328 void 329 Gogo::propagate_writebarrierrec() 330 { 331 std::vector<Named_object*> worklist; 332 Collect_writebarrierrec_functions cwf(&worklist); 333 this->traverse(&cwf); 334 335 Collect_callees cc(&worklist); 336 337 while (!worklist.empty()) 338 { 339 Named_object* no = worklist.back(); 340 worklist.pop_back(); 341 342 unsigned int pragmas = no->func_value()->pragmas(); 343 if ((pragmas & GOPRAGMA_MARK) != 0) 344 { 345 // We've already seen this function. 346 continue; 347 } 348 if ((pragmas & GOPRAGMA_YESWRITEBARRIERREC) != 0) 349 { 350 // We don't want to propagate //go:nowritebarrierrec into 351 // this function or it's callees. 352 continue; 353 } 354 355 no->func_value()->set_pragmas(pragmas 356 | GOPRAGMA_NOWRITEBARRIER 357 | GOPRAGMA_MARK); 358 359 no->func_value()->traverse(&cc); 360 } 361 } 362 363 // Add write barriers to the IR. This are required by the concurrent 364 // garbage collector. A write barrier is needed for any write of a 365 // pointer into memory controlled by the garbage collector. Write 366 // barriers are not required for writes to local variables that live 367 // on the stack. Write barriers are only required when the runtime 368 // enables them, which can be checked using a run time check on 369 // runtime.writeBarrier.enabled. 370 // 371 // Essentially, for each assignment A = B, where A is or contains a 372 // pointer, and where A is not, or at any rate may not be, a stack 373 // variable, we rewrite it into 374 // if runtime.writeBarrier.enabled { 375 // typedmemmove(typeof(A), &A, &B) 376 // } else { 377 // A = B 378 // } 379 // 380 // The test of runtime.writeBarrier.Enabled is implemented by treating 381 // the variable as a *uint32, and testing *runtime.writeBarrier != 0. 382 // This is compatible with the definition in the runtime package. 383 // 384 // For types that are pointer shared (pointers, maps, chans, funcs), 385 // we replaced the call to typedmemmove with gcWriteBarrier(&A, B). 386 // As far as the GC is concerned, all pointers are the same, so it 387 // doesn't need the type descriptor. 388 // 389 // There are possible optimizations that are not implemented. 390 // 391 // runtime.writeBarrier can only change when the goroutine is 392 // preempted, which in practice means when a call is made into the 393 // runtime package, so we could optimize by only testing it once 394 // between function calls. 395 // 396 // A slice could be handled with a call to gcWriteBarrier plus two 397 // integer moves. 398 399 // Traverse the IR adding write barriers. 400 401 class Write_barriers : public Traverse 402 { 403 public: 404 Write_barriers(Gogo* gogo) 405 : Traverse(traverse_functions 406 | traverse_blocks 407 | traverse_variables 408 | traverse_statements), 409 gogo_(gogo), function_(NULL), statements_added_(), 410 nonwb_pointers_() 411 { } 412 413 int 414 function(Named_object*); 415 416 int 417 block(Block*); 418 419 int 420 variable(Named_object*); 421 422 int 423 statement(Block*, size_t* pindex, Statement*); 424 425 private: 426 // General IR. 427 Gogo* gogo_; 428 // Current function. 429 Function* function_; 430 // Statements introduced. 431 Statement_inserter::Statements statements_added_; 432 // Within a single block, pointer variables that point to values 433 // that do not need write barriers. 434 Unordered_set(const Named_object*) nonwb_pointers_; 435 }; 436 437 // Traverse a function. Just record it for later. 438 439 int 440 Write_barriers::function(Named_object* no) 441 { 442 go_assert(this->function_ == NULL); 443 this->function_ = no->func_value(); 444 int t = this->function_->traverse(this); 445 this->function_ = NULL; 446 447 if (t == TRAVERSE_EXIT) 448 return t; 449 return TRAVERSE_SKIP_COMPONENTS; 450 } 451 452 // Traverse a block. Clear anything we know about local pointer 453 // variables. 454 455 int 456 Write_barriers::block(Block*) 457 { 458 this->nonwb_pointers_.clear(); 459 return TRAVERSE_CONTINUE; 460 } 461 462 // Insert write barriers for a global variable: ensure that variable 463 // initialization is handled correctly. This is rarely needed, since 464 // we currently don't enable background GC until after all global 465 // variables are initialized. But we do need this if an init function 466 // calls runtime.GC. 467 468 int 469 Write_barriers::variable(Named_object* no) 470 { 471 // We handle local variables in the variable declaration statement. 472 // We only have to handle global variables here. 473 if (!no->is_variable()) 474 return TRAVERSE_CONTINUE; 475 Variable* var = no->var_value(); 476 if (!var->is_global()) 477 return TRAVERSE_CONTINUE; 478 479 // Nothing to do if there is no initializer. 480 Expression* init = var->init(); 481 if (init == NULL) 482 return TRAVERSE_CONTINUE; 483 484 // Nothing to do for variables that do not contain any pointers. 485 if (!var->type()->has_pointer()) 486 return TRAVERSE_CONTINUE; 487 488 // Nothing to do if the initializer is static. 489 init = Expression::make_cast(var->type(), init, var->location()); 490 if (!var->has_pre_init() && init->is_static_initializer()) 491 return TRAVERSE_CONTINUE; 492 493 // Nothing to do for a type that can not be in the heap, or a 494 // pointer to a type that can not be in the heap. 495 if (!var->type()->in_heap()) 496 return TRAVERSE_CONTINUE; 497 if (var->type()->points_to() != NULL && !var->type()->points_to()->in_heap()) 498 return TRAVERSE_CONTINUE; 499 500 // Otherwise change the initializer into a pre_init assignment 501 // statement with a write barrier. 502 503 // We can't check for a dependency of the variable on itself after 504 // we make this change, because the preinit statement will always 505 // depend on the variable (since it assigns to it). So check for a 506 // self-dependency now. 507 this->gogo_->check_self_dep(no); 508 509 // Replace the initializer. 510 Location loc = init->location(); 511 Expression* ref = Expression::make_var_reference(no, loc); 512 513 Statement_inserter inserter(this->gogo_, var, &this->statements_added_); 514 Statement* s = this->gogo_->assign_with_write_barrier(NULL, NULL, &inserter, 515 ref, init, loc); 516 this->statements_added_.insert(s); 517 518 var->add_preinit_statement(this->gogo_, s); 519 var->clear_init(); 520 521 return TRAVERSE_CONTINUE; 522 } 523 524 // Insert write barriers for statements. 525 526 int 527 Write_barriers::statement(Block* block, size_t* pindex, Statement* s) 528 { 529 if (this->statements_added_.find(s) != this->statements_added_.end()) 530 return TRAVERSE_SKIP_COMPONENTS; 531 532 switch (s->classification()) 533 { 534 default: 535 break; 536 537 case Statement::STATEMENT_VARIABLE_DECLARATION: 538 { 539 Variable_declaration_statement* vds = 540 s->variable_declaration_statement(); 541 Named_object* no = vds->var(); 542 Variable* var = no->var_value(); 543 544 // We may need to emit a write barrier for the initialization 545 // of the variable. 546 547 // Nothing to do for a variable with no initializer. 548 Expression* init = var->init(); 549 if (init == NULL) 550 break; 551 552 // Nothing to do if the variable is not in the heap. Only 553 // local variables get declaration statements, and local 554 // variables on the stack do not require write barriers. 555 if (!var->is_in_heap()) 556 { 557 // If this is a pointer variable, and assigning through 558 // the initializer does not require a write barrier, 559 // record that fact. 560 if (var->type()->points_to() != NULL 561 && this->gogo_->is_nonwb_pointer(init, &this->nonwb_pointers_)) 562 this->nonwb_pointers_.insert(no); 563 564 break; 565 } 566 567 // Nothing to do if the variable does not contain any pointers. 568 if (!var->type()->has_pointer()) 569 break; 570 571 // Nothing to do for a type that can not be in the heap, or a 572 // pointer to a type that can not be in the heap. 573 if (!var->type()->in_heap()) 574 break; 575 if (var->type()->points_to() != NULL 576 && !var->type()->points_to()->in_heap()) 577 break; 578 579 // Otherwise initialize the variable with a write barrier. 580 581 Function* function = this->function_; 582 Location loc = init->location(); 583 Statement_inserter inserter(block, pindex, &this->statements_added_); 584 585 // Insert the variable declaration statement with no 586 // initializer, so that the variable exists. 587 var->clear_init(); 588 inserter.insert(s); 589 590 // Create a statement that initializes the variable with a 591 // write barrier. 592 Expression* ref = Expression::make_var_reference(no, loc); 593 Statement* assign = this->gogo_->assign_with_write_barrier(function, 594 block, 595 &inserter, 596 ref, init, 597 loc); 598 this->statements_added_.insert(assign); 599 600 // Replace the old variable declaration statement with the new 601 // initialization. 602 block->replace_statement(*pindex, assign); 603 } 604 break; 605 606 case Statement::STATEMENT_ASSIGNMENT: 607 { 608 Assignment_statement* as = s->assignment_statement(); 609 610 Expression* lhs = as->lhs(); 611 Expression* rhs = as->rhs(); 612 613 // Keep track of variables whose values do not escape. 614 Var_expression* lhsve = lhs->var_expression(); 615 if (lhsve != NULL && lhsve->type()->points_to() != NULL) 616 { 617 Named_object* no = lhsve->named_object(); 618 if (this->gogo_->is_nonwb_pointer(rhs, &this->nonwb_pointers_)) 619 this->nonwb_pointers_.insert(no); 620 else 621 this->nonwb_pointers_.erase(no); 622 } 623 624 if (as->omit_write_barrier()) 625 break; 626 627 // We may need to emit a write barrier for the assignment. 628 629 if (!this->gogo_->assign_needs_write_barrier(lhs, 630 &this->nonwb_pointers_)) 631 break; 632 633 // Change the assignment to use a write barrier. 634 Function* function = this->function_; 635 Location loc = as->location(); 636 Statement_inserter inserter = 637 Statement_inserter(block, pindex, &this->statements_added_); 638 Statement* assign = this->gogo_->assign_with_write_barrier(function, 639 block, 640 &inserter, 641 lhs, rhs, 642 loc); 643 this->statements_added_.insert(assign); 644 block->replace_statement(*pindex, assign); 645 } 646 break; 647 } 648 649 return TRAVERSE_CONTINUE; 650 } 651 652 // The write barrier pass. 653 654 void 655 Gogo::add_write_barriers() 656 { 657 if (saw_errors()) 658 return; 659 660 Mark_address_taken mat(this); 661 this->traverse(&mat); 662 663 if (this->compiling_runtime() && this->package_name() == "runtime") 664 { 665 this->propagate_writebarrierrec(); 666 667 Check_escape chk(this); 668 this->traverse(&chk); 669 } 670 671 Write_barriers wb(this); 672 this->traverse(&wb); 673 } 674 675 // Return the runtime.writeBarrier variable. 676 677 Named_object* 678 Gogo::write_barrier_variable() 679 { 680 static Named_object* write_barrier_var; 681 if (write_barrier_var == NULL) 682 { 683 Location bloc = Linemap::predeclared_location(); 684 685 Type* bool_type = Type::lookup_bool_type(); 686 Array_type* pad_type = 687 Type::make_array_type(Type::lookup_integer_type("byte"), 688 Expression::make_integer_ul(3, NULL, bloc)); 689 Type* uint64_type = Type::lookup_integer_type("uint64"); 690 Type* wb_type = Type::make_builtin_struct_type(5, 691 "enabled", bool_type, 692 "pad", pad_type, 693 "needed", bool_type, 694 "cgo", bool_type, 695 "alignme", uint64_type); 696 697 Variable* var = new Variable(wb_type, NULL, 698 true, false, false, bloc); 699 700 bool add_to_globals; 701 Package* package = this->add_imported_package("runtime", "_", false, 702 "runtime", "runtime", 703 bloc, &add_to_globals); 704 write_barrier_var = Named_object::make_variable("writeBarrier", 705 package, var); 706 } 707 708 return write_barrier_var; 709 } 710 711 // Return whether an assignment that sets LHS needs a write barrier. 712 // NONWB_POINTERS is a set of variables that point to values that do 713 // not need write barriers. 714 715 bool 716 Gogo::assign_needs_write_barrier( 717 Expression* lhs, 718 Unordered_set(const Named_object*)* nonwb_pointers) 719 { 720 // Nothing to do if the variable does not contain any pointers. 721 if (!lhs->type()->has_pointer()) 722 return false; 723 724 // An assignment to a field or an array index is handled like an 725 // assignment to the struct. 726 while (true) 727 { 728 // Nothing to do for a type that can not be in the heap, or a 729 // pointer to a type that can not be in the heap. We check this 730 // at each level of a struct. 731 if (!lhs->type()->in_heap()) 732 return false; 733 if (lhs->type()->points_to() != NULL 734 && !lhs->type()->points_to()->in_heap()) 735 return false; 736 737 // For a struct assignment, we don't need a write barrier if all 738 // the field types can not be in the heap. 739 Struct_type* st = lhs->type()->struct_type(); 740 if (st != NULL) 741 { 742 bool in_heap = false; 743 const Struct_field_list* fields = st->fields(); 744 for (Struct_field_list::const_iterator p = fields->begin(); 745 p != fields->end(); 746 p++) 747 { 748 Type* ft = p->type(); 749 if (!ft->has_pointer()) 750 continue; 751 if (!ft->in_heap()) 752 continue; 753 if (ft->points_to() != NULL && !ft->points_to()->in_heap()) 754 continue; 755 in_heap = true; 756 break; 757 } 758 if (!in_heap) 759 return false; 760 } 761 762 Field_reference_expression* fre = lhs->field_reference_expression(); 763 if (fre != NULL) 764 { 765 lhs = fre->expr(); 766 continue; 767 } 768 769 Array_index_expression* aie = lhs->array_index_expression(); 770 if (aie != NULL 771 && aie->end() == NULL 772 && !aie->array()->type()->is_slice_type()) 773 { 774 lhs = aie->array(); 775 continue; 776 } 777 778 break; 779 } 780 781 // Nothing to do for an assignment to a temporary. 782 if (lhs->temporary_reference_expression() != NULL) 783 return false; 784 785 // Nothing to do for an assignment to a sink. 786 if (lhs->is_sink_expression()) 787 return false; 788 789 // Nothing to do for an assignment to a local variable that is not 790 // on the heap. 791 Var_expression* ve = lhs->var_expression(); 792 if (ve != NULL) 793 { 794 Named_object* no = ve->named_object(); 795 if (no->is_variable()) 796 { 797 Variable* var = no->var_value(); 798 if (!var->is_global() && !var->is_in_heap()) 799 return false; 800 } 801 else if (no->is_result_variable()) 802 { 803 Result_variable* rvar = no->result_var_value(); 804 if (!rvar->is_in_heap()) 805 return false; 806 } 807 } 808 809 // Nothing to do for an assignment to *(convert(&x)) where 810 // x is local variable or a temporary variable. 811 Unary_expression* ue = lhs->unary_expression(); 812 if (ue != NULL 813 && ue->op() == OPERATOR_MULT 814 && this->is_nonwb_pointer(ue->operand(), nonwb_pointers)) 815 return false; 816 817 // Write barrier needed in other cases. 818 return true; 819 } 820 821 // Return whether EXPR is the address of a variable that can be set 822 // without a write barrier. That is, if this returns true, then an 823 // assignment to *EXPR does not require a write barrier. 824 // NONWB_POINTERS is a set of variables that point to values that do 825 // not need write barriers. 826 827 bool 828 Gogo::is_nonwb_pointer(Expression* expr, 829 Unordered_set(const Named_object*)* nonwb_pointers) 830 { 831 while (true) 832 { 833 if (expr->conversion_expression() != NULL) 834 expr = expr->conversion_expression()->expr(); 835 else if (expr->unsafe_conversion_expression() != NULL) 836 expr = expr->unsafe_conversion_expression()->expr(); 837 else 838 break; 839 } 840 841 Var_expression* ve = expr->var_expression(); 842 if (ve != NULL 843 && nonwb_pointers != NULL 844 && nonwb_pointers->find(ve->named_object()) != nonwb_pointers->end()) 845 return true; 846 847 Unary_expression* ue = expr->unary_expression(); 848 if (ue == NULL || ue->op() != OPERATOR_AND) 849 return false; 850 if (this->assign_needs_write_barrier(ue->operand(), nonwb_pointers)) 851 return false; 852 return true; 853 } 854 855 // Return a statement that sets LHS to RHS using a write barrier. 856 // ENCLOSING is the enclosing block. 857 858 Statement* 859 Gogo::assign_with_write_barrier(Function* function, Block* enclosing, 860 Statement_inserter* inserter, Expression* lhs, 861 Expression* rhs, Location loc) 862 { 863 if (function != NULL && (function->pragmas() & GOPRAGMA_NOWRITEBARRIER) != 0) 864 go_error_at(loc, "write barrier prohibited"); 865 866 Type* type = lhs->type(); 867 go_assert(type->has_pointer()); 868 869 Expression* addr; 870 if (lhs->unary_expression() != NULL 871 && lhs->unary_expression()->op() == OPERATOR_MULT) 872 addr = lhs->unary_expression()->operand(); 873 else 874 { 875 addr = Expression::make_unary(OPERATOR_AND, lhs, loc); 876 addr->unary_expression()->set_does_not_escape(); 877 } 878 Temporary_statement* lhs_temp = Statement::make_temporary(NULL, addr, loc); 879 inserter->insert(lhs_temp); 880 lhs = Expression::make_temporary_reference(lhs_temp, loc); 881 882 if (!Type::are_identical(type, rhs->type(), 883 Type::COMPARE_ERRORS | Type::COMPARE_TAGS, 884 NULL) 885 && rhs->type()->interface_type() != NULL 886 && !rhs->is_multi_eval_safe()) 887 { 888 // May need a temporary for interface conversion. 889 Temporary_statement* temp = Statement::make_temporary(NULL, rhs, loc); 890 inserter->insert(temp); 891 rhs = Expression::make_temporary_reference(temp, loc); 892 } 893 rhs = Expression::convert_for_assignment(this, type, rhs, loc); 894 Temporary_statement* rhs_temp = NULL; 895 if (!rhs->is_multi_eval_safe()) 896 { 897 rhs_temp = Statement::make_temporary(NULL, rhs, loc); 898 inserter->insert(rhs_temp); 899 rhs = Expression::make_temporary_reference(rhs_temp, loc); 900 } 901 902 Expression* indir = 903 Expression::make_dereference(lhs, Expression::NIL_CHECK_DEFAULT, loc); 904 Statement* assign = Statement::make_assignment(indir, rhs, loc); 905 906 lhs = Expression::make_temporary_reference(lhs_temp, loc); 907 if (rhs_temp != NULL) 908 rhs = Expression::make_temporary_reference(rhs_temp, loc); 909 910 Type* unsafe_ptr_type = Type::make_pointer_type(Type::make_void_type()); 911 lhs = Expression::make_unsafe_cast(unsafe_ptr_type, lhs, loc); 912 913 Type* uintptr_type = Type::lookup_integer_type("uintptr"); 914 Expression* call; 915 switch (type->base()->classification()) 916 { 917 default: 918 go_unreachable(); 919 920 case Type::TYPE_ERROR: 921 return assign; 922 923 case Type::TYPE_POINTER: 924 case Type::TYPE_FUNCTION: 925 case Type::TYPE_MAP: 926 case Type::TYPE_CHANNEL: 927 { 928 // These types are all represented by a single pointer. 929 rhs = Expression::make_unsafe_cast(uintptr_type, rhs, loc); 930 call = Runtime::make_call(Runtime::GCWRITEBARRIER, loc, 2, lhs, rhs); 931 } 932 break; 933 934 case Type::TYPE_STRING: 935 { 936 // Assign the length field directly. 937 Expression* llen = 938 Expression::make_string_info(indir->copy(), 939 Expression::STRING_INFO_LENGTH, 940 loc); 941 Expression* rlen = 942 Expression::make_string_info(rhs, 943 Expression::STRING_INFO_LENGTH, 944 loc); 945 Statement* as = Statement::make_assignment(llen, rlen, loc); 946 inserter->insert(as); 947 948 // Assign the data field with a write barrier. 949 lhs = 950 Expression::make_string_info(indir->copy(), 951 Expression::STRING_INFO_DATA, 952 loc); 953 rhs = 954 Expression::make_string_info(rhs, 955 Expression::STRING_INFO_DATA, 956 loc); 957 assign = Statement::make_assignment(lhs, rhs, loc); 958 lhs = Expression::make_unary(OPERATOR_AND, lhs, loc); 959 rhs = Expression::make_unsafe_cast(uintptr_type, rhs, loc); 960 call = Runtime::make_call(Runtime::GCWRITEBARRIER, loc, 2, lhs, rhs); 961 } 962 break; 963 964 case Type::TYPE_INTERFACE: 965 { 966 // Assign the first field directly. 967 // The first field is either a type descriptor or a method table. 968 // Type descriptors are either statically created, or created by 969 // the reflect package. For the latter the reflect package keeps 970 // all references. 971 // Method tables are either statically created or persistently 972 // allocated. 973 // In all cases they don't need a write barrier. 974 Expression* ltab = 975 Expression::make_interface_info(indir->copy(), 976 Expression::INTERFACE_INFO_METHODS, 977 loc); 978 Expression* rtab = 979 Expression::make_interface_info(rhs, 980 Expression::INTERFACE_INFO_METHODS, 981 loc); 982 Statement* as = Statement::make_assignment(ltab, rtab, loc); 983 inserter->insert(as); 984 985 // Assign the data field with a write barrier. 986 lhs = 987 Expression::make_interface_info(indir->copy(), 988 Expression::INTERFACE_INFO_OBJECT, 989 loc); 990 rhs = 991 Expression::make_interface_info(rhs, 992 Expression::INTERFACE_INFO_OBJECT, 993 loc); 994 assign = Statement::make_assignment(lhs, rhs, loc); 995 lhs = Expression::make_unary(OPERATOR_AND, lhs, loc); 996 rhs = Expression::make_unsafe_cast(uintptr_type, rhs, loc); 997 call = Runtime::make_call(Runtime::GCWRITEBARRIER, loc, 2, lhs, rhs); 998 } 999 break; 1000 1001 case Type::TYPE_ARRAY: 1002 if (type->is_slice_type()) 1003 { 1004 // Assign the lenth fields directly. 1005 Expression* llen = 1006 Expression::make_slice_info(indir->copy(), 1007 Expression::SLICE_INFO_LENGTH, 1008 loc); 1009 Expression* rlen = 1010 Expression::make_slice_info(rhs, 1011 Expression::SLICE_INFO_LENGTH, 1012 loc); 1013 Statement* as = Statement::make_assignment(llen, rlen, loc); 1014 inserter->insert(as); 1015 1016 // Assign the capacity fields directly. 1017 Expression* lcap = 1018 Expression::make_slice_info(indir->copy(), 1019 Expression::SLICE_INFO_CAPACITY, 1020 loc); 1021 Expression* rcap = 1022 Expression::make_slice_info(rhs, 1023 Expression::SLICE_INFO_CAPACITY, 1024 loc); 1025 as = Statement::make_assignment(lcap, rcap, loc); 1026 inserter->insert(as); 1027 1028 // Assign the data field with a write barrier. 1029 lhs = 1030 Expression::make_slice_info(indir->copy(), 1031 Expression::SLICE_INFO_VALUE_POINTER, 1032 loc); 1033 rhs = 1034 Expression::make_slice_info(rhs, 1035 Expression::SLICE_INFO_VALUE_POINTER, 1036 loc); 1037 assign = Statement::make_assignment(lhs, rhs, loc); 1038 lhs = Expression::make_unary(OPERATOR_AND, lhs, loc); 1039 rhs = Expression::make_unsafe_cast(uintptr_type, rhs, loc); 1040 call = Runtime::make_call(Runtime::GCWRITEBARRIER, loc, 2, lhs, rhs); 1041 break; 1042 } 1043 // fallthrough 1044 1045 case Type::TYPE_STRUCT: 1046 if (type->is_direct_iface_type()) 1047 { 1048 rhs = Expression::unpack_direct_iface(rhs, loc); 1049 rhs = Expression::make_unsafe_cast(uintptr_type, rhs, loc); 1050 call = Runtime::make_call(Runtime::GCWRITEBARRIER, loc, 2, lhs, rhs); 1051 } 1052 else 1053 { 1054 // TODO: split assignments for small struct/array? 1055 rhs = Expression::make_unary(OPERATOR_AND, rhs, loc); 1056 rhs->unary_expression()->set_does_not_escape(); 1057 call = Runtime::make_call(Runtime::TYPEDMEMMOVE, loc, 3, 1058 Expression::make_type_descriptor(type, loc), 1059 lhs, rhs); 1060 } 1061 break; 1062 } 1063 1064 return this->check_write_barrier(enclosing, assign, 1065 Statement::make_statement(call, false)); 1066 } 1067 1068 // Return a statement that tests whether write barriers are enabled 1069 // and executes either the efficient code or the write barrier 1070 // function call, depending. 1071 1072 Statement* 1073 Gogo::check_write_barrier(Block* enclosing, Statement* without, 1074 Statement* with) 1075 { 1076 Location loc = without->location(); 1077 Named_object* wb = this->write_barrier_variable(); 1078 // We pretend that writeBarrier is a uint32, so that we do a 1079 // 32-bit load. That is what the gc toolchain does. 1080 Type* void_type = Type::make_void_type(); 1081 Type* unsafe_pointer_type = Type::make_pointer_type(void_type); 1082 Type* uint32_type = Type::lookup_integer_type("uint32"); 1083 Type* puint32_type = Type::make_pointer_type(uint32_type); 1084 Expression* ref = Expression::make_var_reference(wb, loc); 1085 ref = Expression::make_unary(OPERATOR_AND, ref, loc); 1086 ref = Expression::make_cast(unsafe_pointer_type, ref, loc); 1087 ref = Expression::make_cast(puint32_type, ref, loc); 1088 ref = Expression::make_dereference(ref, 1089 Expression::NIL_CHECK_NOT_NEEDED, loc); 1090 Expression* zero = Expression::make_integer_ul(0, ref->type(), loc); 1091 Expression* cond = Expression::make_binary(OPERATOR_EQEQ, ref, zero, loc); 1092 1093 Block* then_block = new Block(enclosing, loc); 1094 then_block->add_statement(without); 1095 1096 Block* else_block = new Block(enclosing, loc); 1097 else_block->add_statement(with); 1098 1099 return Statement::make_if_statement(cond, then_block, else_block, loc); 1100 }