| Index: runtime/vm/flow_graph_compiler_arm.cc | 
| diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc | 
| index b4df97c4b0ca2491d393f3f4e2d04da26ad692ff..5781c29fd76bdbbc8776da1b2703058578411ad8 100644 | 
| --- a/runtime/vm/flow_graph_compiler_arm.cc | 
| +++ b/runtime/vm/flow_graph_compiler_arm.cc | 
| @@ -100,11 +100,14 @@ RawTypedData* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler, | 
|  | 
| Zone* zone = compiler->zone(); | 
|  | 
| +  // Current PP, FP, and PC. | 
| builder->AddPp(current->function(), slot_ix++); | 
| -  builder->AddPcMarker(Function::Handle(zone), slot_ix++); | 
| builder->AddCallerFp(slot_ix++); | 
| builder->AddReturnAddress(current->function(), deopt_id(), slot_ix++); | 
|  | 
| +  // Callee's PC marker is not used anymore. Pass Function::null() to set to 0. | 
| +  builder->AddPcMarker(Function::Handle(zone), slot_ix++); | 
| + | 
| // Emit all values that are needed for materialization as a part of the | 
| // expression stack for the bottom-most frame. This guarantees that GC | 
| // will be able to find them during materialization. | 
| @@ -120,8 +123,8 @@ RawTypedData* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler, | 
| Environment* previous = current; | 
| current = current->outer(); | 
| while (current != NULL) { | 
| +    // PP, FP, and PC. | 
| builder->AddPp(current->function(), slot_ix++); | 
| -    builder->AddPcMarker(previous->function(), slot_ix++); | 
| builder->AddCallerFp(slot_ix++); | 
|  | 
| // For any outer environment the deopt id is that of the call instruction | 
| @@ -131,6 +134,9 @@ RawTypedData* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler, | 
| Isolate::ToDeoptAfter(current->deopt_id()), | 
| slot_ix++); | 
|  | 
| +    // PC marker. | 
| +    builder->AddPcMarker(previous->function(), slot_ix++); | 
| + | 
| // The values of outgoing arguments can be changed from the inlined call so | 
| // we must read them from the previous environment. | 
| for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { | 
| @@ -155,12 +161,14 @@ RawTypedData* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler, | 
| // The previous pointer is now the outermost environment. | 
| ASSERT(previous != NULL); | 
|  | 
| -  // Set slots for the outermost environment. | 
| +  // For the outermost environment, set caller PC, caller PP, and caller FP. | 
| builder->AddCallerPp(slot_ix++); | 
| -  builder->AddPcMarker(previous->function(), slot_ix++); | 
| builder->AddCallerFp(slot_ix++); | 
| builder->AddCallerPc(slot_ix++); | 
|  | 
| +  // PC marker. | 
| +  builder->AddPcMarker(previous->function(), slot_ix++); | 
| + | 
| // For the outermost environment, set the incoming arguments. | 
| for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { | 
| builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), slot_ix++); | 
| @@ -187,7 +195,6 @@ void CompilerDeoptInfoWithStub::GenerateCode(FlowGraphCompiler* compiler, | 
| // LR may be live. It will be clobbered by BranchLink, so cache it in IP. | 
| // It will be restored at the top of the deoptimization stub, specifically in | 
| // GenerateDeoptimizationSequence in stub_code_arm.cc. | 
| -  __ Push(CODE_REG); | 
| __ mov(IP, Operand(LR)); | 
| __ BranchLink(*StubCode::Deoptimize_entry()); | 
| set_pc_offset(assem->CodeSize()); | 
| @@ -752,13 +759,13 @@ void FlowGraphCompiler::CopyParameters() { | 
| const int min_num_pos_args = num_fixed_params; | 
| const int max_num_pos_args = num_fixed_params + num_opt_pos_params; | 
|  | 
| -  __ ldr(R10, FieldAddress(R4, ArgumentsDescriptor::positional_count_offset())); | 
| +  __ ldr(R9, FieldAddress(R4, ArgumentsDescriptor::positional_count_offset())); | 
| // Check that min_num_pos_args <= num_pos_args. | 
| Label wrong_num_arguments; | 
| -  __ CompareImmediate(R10, Smi::RawValue(min_num_pos_args)); | 
| +  __ CompareImmediate(R9, Smi::RawValue(min_num_pos_args)); | 
| __ b(&wrong_num_arguments, LT); | 
| // Check that num_pos_args <= max_num_pos_args. | 
| -  __ CompareImmediate(R10, Smi::RawValue(max_num_pos_args)); | 
| +  __ CompareImmediate(R9, Smi::RawValue(max_num_pos_args)); | 
| __ b(&wrong_num_arguments, GT); | 
|  | 
| // Copy positional arguments. | 
| @@ -766,30 +773,30 @@ void FlowGraphCompiler::CopyParameters() { | 
| // to fp[kFirstLocalSlotFromFp - i]. | 
|  | 
| __ ldr(R7, FieldAddress(R4, ArgumentsDescriptor::count_offset())); | 
| -  // Since R7 and R10 are Smi, use LSL 1 instead of LSL 2. | 
| +  // Since R7 and R9 are Smi, use LSL 1 instead of LSL 2. | 
| // Let R7 point to the last passed positional argument, i.e. to | 
| // fp[kParamEndSlotFromFp + num_args - (num_pos_args - 1)]. | 
| -  __ sub(R7, R7, Operand(R10)); | 
| +  __ sub(R7, R7, Operand(R9)); | 
| __ add(R7, FP, Operand(R7, LSL, 1)); | 
| __ add(R7, R7, Operand((kParamEndSlotFromFp + 1) * kWordSize)); | 
|  | 
| // Let R6 point to the last copied positional argument, i.e. to | 
| // fp[kFirstLocalSlotFromFp - (num_pos_args - 1)]. | 
| __ AddImmediate(R6, FP, (kFirstLocalSlotFromFp + 1) * kWordSize); | 
| -  __ sub(R6, R6, Operand(R10, LSL, 1));  // R10 is a Smi. | 
| -  __ SmiUntag(R10); | 
| +  __ sub(R6, R6, Operand(R9, LSL, 1));  // R9 is a Smi. | 
| +  __ SmiUntag(R9); | 
| Label loop, loop_condition; | 
| __ b(&loop_condition); | 
| // We do not use the final allocation index of the variable here, i.e. | 
| // scope->VariableAt(i)->index(), because captured variables still need | 
| // to be copied to the context that is not yet allocated. | 
| -  const Address argument_addr(R7, R10, LSL, 2); | 
| -  const Address copy_addr(R6, R10, LSL, 2); | 
| +  const Address argument_addr(R7, R9, LSL, 2); | 
| +  const Address copy_addr(R6, R9, LSL, 2); | 
| __ Bind(&loop); | 
| __ ldr(IP, argument_addr); | 
| __ str(IP, copy_addr); | 
| __ Bind(&loop_condition); | 
| -  __ subs(R10, R10, Operand(1)); | 
| +  __ subs(R9, R9, Operand(1)); | 
| __ b(&loop, PL); | 
|  | 
| // Copy or initialize optional named arguments. | 
| @@ -820,9 +827,9 @@ void FlowGraphCompiler::CopyParameters() { | 
| } | 
| // Generate code handling each optional parameter in alphabetical order. | 
| __ ldr(R7, FieldAddress(R4, ArgumentsDescriptor::count_offset())); | 
| -    __ ldr(R10, | 
| +    __ ldr(R9, | 
| FieldAddress(R4, ArgumentsDescriptor::positional_count_offset())); | 
| -    __ SmiUntag(R10); | 
| +    __ SmiUntag(R9); | 
| // Let R7 point to the first passed argument, i.e. to | 
| // fp[kParamEndSlotFromFp + num_args - 0]; num_args (R7) is Smi. | 
| __ add(R7, FP, Operand(R7, LSL, 1)); | 
| @@ -874,16 +881,16 @@ void FlowGraphCompiler::CopyParameters() { | 
| } | 
| } else { | 
| ASSERT(num_opt_pos_params > 0); | 
| -    __ ldr(R10, | 
| +    __ ldr(R9, | 
| FieldAddress(R4, ArgumentsDescriptor::positional_count_offset())); | 
| -    __ SmiUntag(R10); | 
| +    __ SmiUntag(R9); | 
| for (int i = 0; i < num_opt_pos_params; i++) { | 
| Label next_parameter; | 
| // Handle this optional positional parameter only if k or fewer positional | 
| // arguments have been passed, where k is param_pos, the position of this | 
| // optional parameter in the formal parameter list. | 
| const int param_pos = num_fixed_params + i; | 
| -      __ CompareImmediate(R10, param_pos); | 
| +      __ CompareImmediate(R9, param_pos); | 
| __ b(&next_parameter, GT); | 
| // Load R5 with default argument. | 
| const Object& value = parsed_function().DefaultParameterValueAt(i); | 
| @@ -900,16 +907,20 @@ void FlowGraphCompiler::CopyParameters() { | 
| if (check_correct_named_args) { | 
| __ ldr(R7, FieldAddress(R4, ArgumentsDescriptor::count_offset())); | 
| __ SmiUntag(R7); | 
| -      // Check that R10 equals R7, i.e. no named arguments passed. | 
| -      __ cmp(R10, Operand(R7)); | 
| +      // Check that R9 equals R7, i.e. no named arguments passed. | 
| +      __ cmp(R9, Operand(R7)); | 
| __ b(&all_arguments_processed, EQ); | 
| } | 
| } | 
|  | 
| __ Bind(&wrong_num_arguments); | 
| if (function.IsClosureFunction()) { | 
| -    __ LeaveDartFrame(kKeepCalleePP);  // The arguments are still on the stack. | 
| +    ASSERT(assembler()->constant_pool_allowed()); | 
| +    __ LeaveDartFrame();  // The arguments are still on the stack. | 
| +    // Do not use caller's pool ptr in branch. | 
| +    ASSERT(!assembler()->constant_pool_allowed()); | 
| __ Branch(*StubCode::CallClosureNoSuchMethod_entry()); | 
| +    __ set_constant_pool_allowed(true); | 
| // The noSuchMethod call may return to the caller, but not here. | 
| } else if (check_correct_named_args) { | 
| __ Stop("Wrong arguments"); | 
| @@ -923,17 +934,17 @@ void FlowGraphCompiler::CopyParameters() { | 
| // an issue anymore. | 
|  | 
| // R4 : arguments descriptor array. | 
| -  __ ldr(R10, FieldAddress(R4, ArgumentsDescriptor::count_offset())); | 
| -  __ SmiUntag(R10); | 
| +  __ ldr(R9, FieldAddress(R4, ArgumentsDescriptor::count_offset())); | 
| +  __ SmiUntag(R9); | 
| __ add(R7, FP, Operand((kParamEndSlotFromFp + 1) * kWordSize)); | 
| -  const Address original_argument_addr(R7, R10, LSL, 2); | 
| +  const Address original_argument_addr(R7, R9, LSL, 2); | 
| __ LoadObject(IP, Object::null_object()); | 
| Label null_args_loop, null_args_loop_condition; | 
| __ b(&null_args_loop_condition); | 
| __ Bind(&null_args_loop); | 
| __ str(IP, original_argument_addr); | 
| __ Bind(&null_args_loop_condition); | 
| -  __ subs(R10, R10, Operand(1)); | 
| +  __ subs(R9, R9, Operand(1)); | 
| __ b(&null_args_loop, PL); | 
| } | 
|  | 
| @@ -963,9 +974,6 @@ void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { | 
| } | 
|  | 
|  | 
| -static const Register new_pp = R7; | 
| - | 
| - | 
| void FlowGraphCompiler::EmitFrameEntry() { | 
| const Function& function = parsed_function().function(); | 
| if (CanOptimizeFunction() && | 
| @@ -974,23 +982,33 @@ void FlowGraphCompiler::EmitFrameEntry() { | 
| const Register function_reg = R6; | 
|  | 
| // The pool pointer is not setup before entering the Dart frame. | 
| +    // Preserve PP of caller. | 
| +    __ mov(R7, Operand(PP)); | 
| // Temporarily setup pool pointer for this dart function. | 
| -    __ LoadPoolPointer(new_pp); | 
| +    __ LoadPoolPointer(); | 
| // Load function object from object pool. | 
| -    __ LoadFunctionFromCalleePool(function_reg, function, new_pp); | 
| +    __ LoadObject(function_reg, function);  // Uses PP. | 
| +    // Restore PP of caller. | 
| +    __ mov(PP, Operand(R7)); | 
| +    __ set_constant_pool_allowed(false); | 
| + | 
| +    // Patch point is after the eventually inlined function object. | 
| +    entry_patch_pc_offset_ = assembler()->CodeSize(); | 
|  | 
| -    __ ldr(R3, FieldAddress(function_reg, | 
| +    __ ldr(R7, FieldAddress(function_reg, | 
| Function::usage_counter_offset())); | 
| // Reoptimization of an optimized function is triggered by counting in | 
| // IC stubs, but not at the entry of the function. | 
| if (!is_optimizing()) { | 
| -      __ add(R3, R3, Operand(1)); | 
| -      __ str(R3, FieldAddress(function_reg, | 
| +      __ add(R7, R7, Operand(1)); | 
| +      __ str(R7, FieldAddress(function_reg, | 
| Function::usage_counter_offset())); | 
| } | 
| -    __ CompareImmediate(R3, GetOptimizationThreshold()); | 
| +    __ CompareImmediate(R7, GetOptimizationThreshold()); | 
| ASSERT(function_reg == R6); | 
| -    __ Branch(*StubCode::OptimizeFunction_entry(), kNotPatchable, new_pp, GE); | 
| +    __ Branch(*StubCode::OptimizeFunction_entry(), GE); | 
| +  } else if (!flow_graph().IsCompiledForOsr()) { | 
| +    entry_patch_pc_offset_ = assembler()->CodeSize(); | 
| } | 
| __ Comment("Enter frame"); | 
| if (flow_graph().IsCompiledForOsr()) { | 
| @@ -1053,8 +1071,11 @@ void FlowGraphCompiler::CompileGraph() { | 
| __ Bind(&wrong_num_arguments); | 
| if (function.IsClosureFunction()) { | 
| ASSERT(assembler()->constant_pool_allowed()); | 
| -        __ LeaveDartFrame(kKeepCalleePP);  // Arguments are still on the stack. | 
| +        __ LeaveDartFrame();  // The arguments are still on the stack. | 
| +        // Do not use caller's pool ptr in branch. | 
| +        ASSERT(!assembler()->constant_pool_allowed()); | 
| __ Branch(*StubCode::CallClosureNoSuchMethod_entry()); | 
| +        __ set_constant_pool_allowed(true); | 
| // The noSuchMethod call may return to the caller, but not here. | 
| } else { | 
| __ Stop("Wrong number of arguments"); | 
| @@ -1107,6 +1128,10 @@ void FlowGraphCompiler::CompileGraph() { | 
| __ bkpt(0); | 
| ASSERT(assembler()->constant_pool_allowed()); | 
| GenerateDeferredCode(); | 
| +  // Emit function patching code. This will be swapped with the first 3 | 
| +  // instructions at entry point. | 
| +  patch_code_pc_offset_ = assembler()->CodeSize(); | 
| +  __ BranchPatchable(*StubCode::FixCallersTarget_entry()); | 
|  | 
| if (is_optimizing()) { | 
| lazy_deopt_pc_offset_ = assembler()->CodeSize(); | 
|  |