| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/compiler.h" | 5 #include "vm/compiler.h" |
| 6 | 6 |
| 7 #include "vm/assembler.h" | 7 #include "vm/assembler.h" |
| 8 | 8 |
| 9 #include "vm/ast_printer.h" | 9 #include "vm/ast_printer.h" |
| 10 #include "vm/code_generator.h" | 10 #include "vm/code_generator.h" |
| 11 #include "vm/code_patcher.h" | 11 #include "vm/code_patcher.h" |
| 12 #include "vm/dart_entry.h" | 12 #include "vm/dart_entry.h" |
| 13 #include "vm/debugger.h" | 13 #include "vm/debugger.h" |
| 14 #include "vm/deopt_instructions.h" | 14 #include "vm/deopt_instructions.h" |
| 15 #include "vm/disassembler.h" | |
| 16 #include "vm/exceptions.h" | 15 #include "vm/exceptions.h" |
| 17 #include "vm/flags.h" | 16 #include "vm/flags.h" |
| 18 #include "vm/flow_graph.h" | 17 #include "vm/flow_graph.h" |
| 19 #include "vm/flow_graph_allocator.h" | 18 #include "vm/flow_graph_allocator.h" |
| 20 #include "vm/flow_graph_builder.h" | 19 #include "vm/flow_graph_builder.h" |
| 21 #include "vm/flow_graph_compiler.h" | 20 #include "vm/flow_graph_compiler.h" |
| 22 #include "vm/flow_graph_inliner.h" | 21 #include "vm/flow_graph_inliner.h" |
| 23 #include "vm/flow_graph_optimizer.h" | 22 #include "vm/flow_graph_optimizer.h" |
| 24 #include "vm/flow_graph_type_propagator.h" | 23 #include "vm/flow_graph_type_propagator.h" |
| 25 #include "vm/il_printer.h" | 24 #include "vm/il_printer.h" |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 234 function.SwitchToUnoptimizedCode(); | 233 function.SwitchToUnoptimizedCode(); |
| 235 if (FLAG_trace_compiler) { | 234 if (FLAG_trace_compiler) { |
| 236 OS::Print("--> restoring entry at %#"Px"\n", | 235 OS::Print("--> restoring entry at %#"Px"\n", |
| 237 Code::Handle(function.unoptimized_code()).EntryPoint()); | 236 Code::Handle(function.unoptimized_code()).EntryPoint()); |
| 238 } | 237 } |
| 239 } | 238 } |
| 240 | 239 |
| 241 | 240 |
| 242 // Return false if bailed out. | 241 // Return false if bailed out. |
| 243 static bool CompileParsedFunctionHelper(ParsedFunction* parsed_function, | 242 static bool CompileParsedFunctionHelper(ParsedFunction* parsed_function, |
| 244 bool optimized) { | 243 bool optimized, |
| 244 intptr_t osr_id) { |
| 245 const Function& function = parsed_function->function(); | 245 const Function& function = parsed_function->function(); |
| 246 if (optimized && !function.is_optimizable()) { | 246 if (optimized && !function.is_optimizable()) { |
| 247 return false; | 247 return false; |
| 248 } | 248 } |
| 249 TimerScope timer(FLAG_compiler_stats, &CompilerStats::codegen_timer); | 249 TimerScope timer(FLAG_compiler_stats, &CompilerStats::codegen_timer); |
| 250 bool is_compiled = false; | 250 bool is_compiled = false; |
| 251 Isolate* isolate = Isolate::Current(); | 251 Isolate* isolate = Isolate::Current(); |
| 252 HANDLESCOPE(isolate); | 252 HANDLESCOPE(isolate); |
| 253 const intptr_t prev_deopt_id = isolate->deopt_id(); | 253 const intptr_t prev_deopt_id = isolate->deopt_id(); |
| 254 isolate->set_deopt_id(0); | 254 isolate->set_deopt_id(0); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 274 FLAG_deoptimization_counter_threshold) { | 274 FLAG_deoptimization_counter_threshold) { |
| 275 const Code& unoptimized_code = | 275 const Code& unoptimized_code = |
| 276 Code::Handle(function.unoptimized_code()); | 276 Code::Handle(function.unoptimized_code()); |
| 277 ic_data_array = unoptimized_code.ExtractTypeFeedbackArray(); | 277 ic_data_array = unoptimized_code.ExtractTypeFeedbackArray(); |
| 278 } | 278 } |
| 279 } | 279 } |
| 280 | 280 |
| 281 // Build the flow graph. | 281 // Build the flow graph. |
| 282 FlowGraphBuilder builder(parsed_function, | 282 FlowGraphBuilder builder(parsed_function, |
| 283 ic_data_array, | 283 ic_data_array, |
| 284 NULL); // NULL = not inlining. | 284 NULL, // NULL = not inlining. |
| 285 osr_id); |
| 285 flow_graph = builder.BuildGraph(); | 286 flow_graph = builder.BuildGraph(); |
| 286 } | 287 } |
| 287 | 288 |
| 288 if (FLAG_print_flow_graph || | 289 if (FLAG_print_flow_graph || |
| 289 (optimized && FLAG_print_flow_graph_optimized)) { | 290 (optimized && FLAG_print_flow_graph_optimized)) { |
| 290 FlowGraphPrinter::PrintGraph("Before Optimizations", flow_graph); | 291 if (osr_id == Isolate::kNoDeoptId) { |
| 292 FlowGraphPrinter::PrintGraph("Before Optimizations", flow_graph); |
| 293 } else { |
| 294 FlowGraphPrinter::PrintGraph("For OSR", flow_graph); |
| 295 } |
| 291 } | 296 } |
| 292 | 297 |
| 293 if (optimized) { | 298 if (optimized) { |
| 294 TimerScope timer(FLAG_compiler_stats, | 299 TimerScope timer(FLAG_compiler_stats, |
| 295 &CompilerStats::ssa_timer, | 300 &CompilerStats::ssa_timer, |
| 296 isolate); | 301 isolate); |
| 297 // Transform to SSA (virtual register 0 and no inlining arguments). | 302 // Transform to SSA (virtual register 0 and no inlining arguments). |
| 298 flow_graph->ComputeSSA(0, NULL); | 303 flow_graph->ComputeSSA(0, NULL); |
| 299 DEBUG_ASSERT(flow_graph->VerifyUseLists()); | 304 DEBUG_ASSERT(flow_graph->VerifyUseLists()); |
| 300 if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) { | 305 if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) { |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 495 code.set_is_optimized(optimized); | 500 code.set_is_optimized(optimized); |
| 496 graph_compiler.FinalizePcDescriptors(code); | 501 graph_compiler.FinalizePcDescriptors(code); |
| 497 graph_compiler.FinalizeDeoptInfo(code); | 502 graph_compiler.FinalizeDeoptInfo(code); |
| 498 graph_compiler.FinalizeStackmaps(code); | 503 graph_compiler.FinalizeStackmaps(code); |
| 499 graph_compiler.FinalizeVarDescriptors(code); | 504 graph_compiler.FinalizeVarDescriptors(code); |
| 500 graph_compiler.FinalizeExceptionHandlers(code); | 505 graph_compiler.FinalizeExceptionHandlers(code); |
| 501 graph_compiler.FinalizeComments(code); | 506 graph_compiler.FinalizeComments(code); |
| 502 graph_compiler.FinalizeStaticCallTargetsTable(code); | 507 graph_compiler.FinalizeStaticCallTargetsTable(code); |
| 503 | 508 |
| 504 if (optimized) { | 509 if (optimized) { |
| 505 CodePatcher::PatchEntry(Code::Handle(function.CurrentCode())); | 510 if (osr_id == Isolate::kNoDeoptId) { |
| 511 CodePatcher::PatchEntry(Code::Handle(function.CurrentCode())); |
| 512 if (FLAG_trace_compiler) { |
| 513 OS::Print("--> patching entry %#"Px"\n", |
| 514 Code::Handle(function.unoptimized_code()).EntryPoint()); |
| 515 } |
| 516 } |
| 506 function.SetCode(code); | 517 function.SetCode(code); |
| 507 if (FLAG_trace_compiler) { | |
| 508 OS::Print("--> patching entry %#"Px"\n", | |
| 509 Code::Handle(function.unoptimized_code()).EntryPoint()); | |
| 510 } | |
| 511 | 518 |
| 512 // If not yet present, allocate deoptimization history array. | 519 // If not yet present, allocate deoptimization history array. |
| 513 function.EnsureDeoptHistory(); | 520 function.EnsureDeoptHistory(); |
| 514 | 521 |
| 515 for (intptr_t i = 0; i < guarded_fields.length(); i++) { | 522 for (intptr_t i = 0; i < guarded_fields.length(); i++) { |
| 516 const Field& field = *guarded_fields[i]; | 523 const Field& field = *guarded_fields[i]; |
| 517 field.RegisterDependentCode(code); | 524 field.RegisterDependentCode(code); |
| 518 } | 525 } |
| 519 } else { | 526 } else { |
| 520 function.set_unoptimized_code(code); | 527 function.set_unoptimized_code(code); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 541 return is_compiled; | 548 return is_compiled; |
| 542 } | 549 } |
| 543 | 550 |
| 544 | 551 |
| 545 static void DisassembleCode(const Function& function, bool optimized) { | 552 static void DisassembleCode(const Function& function, bool optimized) { |
| 546 const char* function_fullname = function.ToFullyQualifiedCString(); | 553 const char* function_fullname = function.ToFullyQualifiedCString(); |
| 547 OS::Print("Code for %sfunction '%s' {\n", | 554 OS::Print("Code for %sfunction '%s' {\n", |
| 548 optimized ? "optimized " : "", | 555 optimized ? "optimized " : "", |
| 549 function_fullname); | 556 function_fullname); |
| 550 const Code& code = Code::Handle(function.CurrentCode()); | 557 const Code& code = Code::Handle(function.CurrentCode()); |
| 551 const Instructions& instructions = | 558 code.Disassemble(); |
| 552 Instructions::Handle(code.instructions()); | |
| 553 uword start = instructions.EntryPoint(); | |
| 554 Disassembler::Disassemble(start, | |
| 555 start + instructions.size(), | |
| 556 code.comments()); | |
| 557 OS::Print("}\n"); | 559 OS::Print("}\n"); |
| 558 | 560 |
| 559 OS::Print("Pointer offsets for function: {\n"); | 561 OS::Print("Pointer offsets for function: {\n"); |
| 560 // Pointer offsets are stored in descending order. | 562 // Pointer offsets are stored in descending order. |
| 561 for (intptr_t i = code.pointer_offsets_length() - 1; i >= 0; i--) { | 563 for (intptr_t i = code.pointer_offsets_length() - 1; i >= 0; i--) { |
| 562 const uword addr = code.GetPointerOffsetAt(i) + code.EntryPoint(); | 564 const uword addr = code.GetPointerOffsetAt(i) + code.EntryPoint(); |
| 563 Object& obj = Object::Handle(); | 565 Object& obj = Object::Handle(); |
| 564 obj = *reinterpret_cast<RawObject**>(addr); | 566 obj = *reinterpret_cast<RawObject**>(addr); |
| 565 OS::Print(" %d : %#"Px" '%s'\n", | 567 OS::Print(" %d : %#"Px" '%s'\n", |
| 566 code.GetPointerOffsetAt(i), addr, obj.ToCString()); | 568 code.GetPointerOffsetAt(i), addr, obj.ToCString()); |
| 567 } | 569 } |
| 568 OS::Print("}\n"); | 570 OS::Print("}\n"); |
| 569 | 571 |
| 570 OS::Print("PC Descriptors for function '%s' {\n", function_fullname); | 572 OS::Print("PC Descriptors for function '%s' {\n", function_fullname); |
| 571 PcDescriptors::PrintHeaderString(); | 573 PcDescriptors::PrintHeaderString(); |
| 572 const PcDescriptors& descriptors = | 574 const PcDescriptors& descriptors = |
| 573 PcDescriptors::Handle(code.pc_descriptors()); | 575 PcDescriptors::Handle(code.pc_descriptors()); |
| 574 OS::Print("%s}\n", descriptors.ToCString()); | 576 OS::Print("%s}\n", descriptors.ToCString()); |
| 575 | 577 |
| 578 uword start = Instructions::Handle(code.instructions()).EntryPoint(); |
| 576 const Array& deopt_table = Array::Handle(code.deopt_info_array()); | 579 const Array& deopt_table = Array::Handle(code.deopt_info_array()); |
| 577 intptr_t deopt_table_length = DeoptTable::GetLength(deopt_table); | 580 intptr_t deopt_table_length = DeoptTable::GetLength(deopt_table); |
| 578 if (deopt_table_length > 0) { | 581 if (deopt_table_length > 0) { |
| 579 OS::Print("DeoptInfo: {\n"); | 582 OS::Print("DeoptInfo: {\n"); |
| 580 Smi& offset = Smi::Handle(); | 583 Smi& offset = Smi::Handle(); |
| 581 DeoptInfo& info = DeoptInfo::Handle(); | 584 DeoptInfo& info = DeoptInfo::Handle(); |
| 582 Smi& reason = Smi::Handle(); | 585 Smi& reason = Smi::Handle(); |
| 583 for (intptr_t i = 0; i < deopt_table_length; ++i) { | 586 for (intptr_t i = 0; i < deopt_table_length; ++i) { |
| 584 DeoptTable::GetEntry(deopt_table, i, &offset, &info, &reason); | 587 DeoptTable::GetEntry(deopt_table, i, &offset, &info, &reason); |
| 585 OS::Print("%4"Pd": 0x%"Px" %s (%s)\n", | 588 OS::Print("%4"Pd": 0x%"Px" %s (%s)\n", |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 665 start + offset.Value(), | 668 start + offset.Value(), |
| 666 function.ToFullyQualifiedCString(), | 669 function.ToFullyQualifiedCString(), |
| 667 code.raw()); | 670 code.raw()); |
| 668 } | 671 } |
| 669 OS::Print("}\n"); | 672 OS::Print("}\n"); |
| 670 } | 673 } |
| 671 } | 674 } |
| 672 | 675 |
| 673 | 676 |
| 674 static RawError* CompileFunctionHelper(const Function& function, | 677 static RawError* CompileFunctionHelper(const Function& function, |
| 675 bool optimized) { | 678 bool optimized, |
| 679 intptr_t osr_id) { |
| 676 Isolate* isolate = Isolate::Current(); | 680 Isolate* isolate = Isolate::Current(); |
| 677 StackZone zone(isolate); | 681 StackZone zone(isolate); |
| 678 LongJump* base = isolate->long_jump_base(); | 682 LongJump* base = isolate->long_jump_base(); |
| 679 LongJump jump; | 683 LongJump jump; |
| 680 isolate->set_long_jump_base(&jump); | 684 isolate->set_long_jump_base(&jump); |
| 681 // Skips parsing if we need to only install unoptimized code. | 685 // Skips parsing if we need to only install unoptimized code. |
| 682 if (!optimized && !Code::Handle(function.unoptimized_code()).IsNull()) { | 686 if (!optimized && !Code::Handle(function.unoptimized_code()).IsNull()) { |
| 683 InstallUnoptimizedCode(function); | 687 InstallUnoptimizedCode(function); |
| 684 isolate->set_long_jump_base(base); | 688 isolate->set_long_jump_base(base); |
| 685 return Error::null(); | 689 return Error::null(); |
| 686 } | 690 } |
| 687 if (setjmp(*jump.Set()) == 0) { | 691 if (setjmp(*jump.Set()) == 0) { |
| 688 TIMERSCOPE(time_compilation); | 692 TIMERSCOPE(time_compilation); |
| 689 Timer per_compile_timer(FLAG_trace_compiler, "Compilation time"); | 693 Timer per_compile_timer(FLAG_trace_compiler, "Compilation time"); |
| 690 per_compile_timer.Start(); | 694 per_compile_timer.Start(); |
| 691 ParsedFunction* parsed_function = new ParsedFunction( | 695 ParsedFunction* parsed_function = new ParsedFunction( |
| 692 Function::ZoneHandle(function.raw())); | 696 Function::ZoneHandle(function.raw())); |
| 693 if (FLAG_trace_compiler) { | 697 if (FLAG_trace_compiler) { |
| 694 OS::Print("Compiling %sfunction: '%s' @ token %"Pd", size %"Pd"\n", | 698 OS::Print("Compiling %s%sfunction: '%s' @ token %"Pd", size %"Pd"\n", |
| 699 (osr_id == Isolate::kNoDeoptId ? "" : "osr "), |
| 695 (optimized ? "optimized " : ""), | 700 (optimized ? "optimized " : ""), |
| 696 function.ToFullyQualifiedCString(), | 701 function.ToFullyQualifiedCString(), |
| 697 function.token_pos(), | 702 function.token_pos(), |
| 698 (function.end_token_pos() - function.token_pos())); | 703 (function.end_token_pos() - function.token_pos())); |
| 699 } | 704 } |
| 700 { | 705 { |
| 701 HANDLESCOPE(isolate); | 706 HANDLESCOPE(isolate); |
| 702 Parser::ParseFunction(parsed_function); | 707 Parser::ParseFunction(parsed_function); |
| 703 parsed_function->AllocateVariables(); | 708 parsed_function->AllocateVariables(); |
| 704 } | 709 } |
| 705 | 710 |
| 706 const bool success = | 711 const bool success = |
| 707 CompileParsedFunctionHelper(parsed_function, optimized); | 712 CompileParsedFunctionHelper(parsed_function, optimized, osr_id); |
| 708 if (optimized && !success) { | 713 if (optimized && !success) { |
| 709 // Optimizer bailed out. Disable optimizations and to never try again. | 714 // Optimizer bailed out. Disable optimizations and to never try again. |
| 710 if (FLAG_trace_compiler) { | 715 if (FLAG_trace_compiler) { |
| 711 OS::Print("--> disabling optimizations for '%s'\n", | 716 OS::Print("--> disabling optimizations for '%s'\n", |
| 712 function.ToFullyQualifiedCString()); | 717 function.ToFullyQualifiedCString()); |
| 713 } else if (FLAG_trace_failed_optimization_attempts) { | 718 } else if (FLAG_trace_failed_optimization_attempts) { |
| 714 OS::Print("Cannot optimize: %s\n", function.ToFullyQualifiedCString()); | 719 OS::Print("Cannot optimize: %s\n", function.ToFullyQualifiedCString()); |
| 715 } | 720 } |
| 716 function.set_is_optimizable(false); | 721 function.set_is_optimizable(false); |
| 717 isolate->set_long_jump_base(base); | 722 isolate->set_long_jump_base(base); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 749 isolate->object_store()->clear_sticky_error(); | 754 isolate->object_store()->clear_sticky_error(); |
| 750 isolate->set_long_jump_base(base); | 755 isolate->set_long_jump_base(base); |
| 751 return error.raw(); | 756 return error.raw(); |
| 752 } | 757 } |
| 753 UNREACHABLE(); | 758 UNREACHABLE(); |
| 754 return Error::null(); | 759 return Error::null(); |
| 755 } | 760 } |
| 756 | 761 |
| 757 | 762 |
| 758 RawError* Compiler::CompileFunction(const Function& function) { | 763 RawError* Compiler::CompileFunction(const Function& function) { |
| 759 return CompileFunctionHelper(function, false); // Non-optimized. | 764 return CompileFunctionHelper(function, false, Isolate::kNoDeoptId); |
| 760 } | 765 } |
| 761 | 766 |
| 762 | 767 |
| 763 RawError* Compiler::CompileOptimizedFunction(const Function& function) { | 768 RawError* Compiler::CompileOptimizedFunction(const Function& function, |
| 764 return CompileFunctionHelper(function, true); // Optimized. | 769 intptr_t osr_id) { |
| 770 return CompileFunctionHelper(function, true, osr_id); |
| 765 } | 771 } |
| 766 | 772 |
| 767 | 773 |
| 768 RawError* Compiler::CompileParsedFunction( | 774 RawError* Compiler::CompileParsedFunction( |
| 769 ParsedFunction* parsed_function) { | 775 ParsedFunction* parsed_function) { |
| 770 Isolate* isolate = Isolate::Current(); | 776 Isolate* isolate = Isolate::Current(); |
| 771 LongJump* base = isolate->long_jump_base(); | 777 LongJump* base = isolate->long_jump_base(); |
| 772 LongJump jump; | 778 LongJump jump; |
| 773 isolate->set_long_jump_base(&jump); | 779 isolate->set_long_jump_base(&jump); |
| 774 if (setjmp(*jump.Set()) == 0) { | 780 if (setjmp(*jump.Set()) == 0) { |
| 775 // Non-optimized code generator. | 781 // Non-optimized code generator. |
| 776 CompileParsedFunctionHelper(parsed_function, false); | 782 CompileParsedFunctionHelper(parsed_function, false, Isolate::kNoDeoptId); |
| 777 if (FLAG_disassemble) { | 783 if (FLAG_disassemble) { |
| 778 DisassembleCode(parsed_function->function(), false); | 784 DisassembleCode(parsed_function->function(), false); |
| 779 } | 785 } |
| 780 isolate->set_long_jump_base(base); | 786 isolate->set_long_jump_base(base); |
| 781 return Error::null(); | 787 return Error::null(); |
| 782 } else { | 788 } else { |
| 783 Error& error = Error::Handle(); | 789 Error& error = Error::Handle(); |
| 784 // We got an error during compilation. | 790 // We got an error during compilation. |
| 785 error = isolate->object_store()->sticky_error(); | 791 error = isolate->object_store()->sticky_error(); |
| 786 isolate->object_store()->clear_sticky_error(); | 792 isolate->object_store()->clear_sticky_error(); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 853 // would compile func automatically. We are checking fewer invariants | 859 // would compile func automatically. We are checking fewer invariants |
| 854 // here. | 860 // here. |
| 855 ParsedFunction* parsed_function = new ParsedFunction(func); | 861 ParsedFunction* parsed_function = new ParsedFunction(func); |
| 856 parsed_function->SetNodeSequence(fragment); | 862 parsed_function->SetNodeSequence(fragment); |
| 857 parsed_function->set_default_parameter_values(Array::ZoneHandle()); | 863 parsed_function->set_default_parameter_values(Array::ZoneHandle()); |
| 858 parsed_function->EnsureExpressionTemp(); | 864 parsed_function->EnsureExpressionTemp(); |
| 859 fragment->scope()->AddVariable(parsed_function->expression_temp_var()); | 865 fragment->scope()->AddVariable(parsed_function->expression_temp_var()); |
| 860 parsed_function->AllocateVariables(); | 866 parsed_function->AllocateVariables(); |
| 861 | 867 |
| 862 // Non-optimized code generator. | 868 // Non-optimized code generator. |
| 863 CompileParsedFunctionHelper(parsed_function, false); | 869 CompileParsedFunctionHelper(parsed_function, false, Isolate::kNoDeoptId); |
| 864 | 870 |
| 865 const Object& result = Object::Handle( | 871 const Object& result = Object::Handle( |
| 866 DartEntry::InvokeFunction(func, Object::empty_array())); | 872 DartEntry::InvokeFunction(func, Object::empty_array())); |
| 867 isolate->set_long_jump_base(base); | 873 isolate->set_long_jump_base(base); |
| 868 return result.raw(); | 874 return result.raw(); |
| 869 } else { | 875 } else { |
| 870 const Object& result = | 876 const Object& result = |
| 871 Object::Handle(isolate->object_store()->sticky_error()); | 877 Object::Handle(isolate->object_store()->sticky_error()); |
| 872 isolate->object_store()->clear_sticky_error(); | 878 isolate->object_store()->clear_sticky_error(); |
| 873 isolate->set_long_jump_base(base); | 879 isolate->set_long_jump_base(base); |
| 874 return result.raw(); | 880 return result.raw(); |
| 875 } | 881 } |
| 876 UNREACHABLE(); | 882 UNREACHABLE(); |
| 877 return Object::null(); | 883 return Object::null(); |
| 878 } | 884 } |
| 879 | 885 |
| 880 } // namespace dart | 886 } // namespace dart |
| OLD | NEW |