| Index: src/arm64/code-stubs-arm64.cc | 
| diff --git a/src/arm64/code-stubs-arm64.cc b/src/arm64/code-stubs-arm64.cc | 
| index 716910ea91b3573e0d664a92552c43adb0141c4a..78383c3248349e610d6e36703402ff15f5f9860d 100644 | 
| --- a/src/arm64/code-stubs-arm64.cc | 
| +++ b/src/arm64/code-stubs-arm64.cc | 
| @@ -1505,191 +1505,107 @@ void LoadIndexedStringStub::Generate(MacroAssembler* masm) { | 
| } | 
|  | 
|  | 
| -void InstanceofStub::Generate(MacroAssembler* masm) { | 
| -  // Stack on entry: | 
| -  // jssp[0]: function. | 
| -  // jssp[8]: object. | 
| -  // | 
| -  // Returns result in x0. Zero indicates instanceof, smi 1 indicates not | 
| -  // instanceof. | 
| - | 
| -  Register result = x0; | 
| -  Register function = right(); | 
| -  Register object = left(); | 
| -  Register scratch1 = x6; | 
| -  Register scratch2 = x7; | 
| -  Register res_true = x8; | 
| -  Register res_false = x9; | 
| -  // Only used if there was an inline map check site. (See | 
| -  // LCodeGen::DoInstanceOfKnownGlobal().) | 
| -  Register map_check_site = x4; | 
| -  // Delta for the instructions generated between the inline map check and the | 
| -  // instruction setting the result. | 
| -  const int32_t kDeltaToLoadBoolResult = 4 * kInstructionSize; | 
| - | 
| -  Label not_js_object, slow; | 
| - | 
| -  if (!HasArgsInRegisters()) { | 
| -    __ Pop(function, object); | 
| -  } | 
| - | 
| -  if (ReturnTrueFalseObject()) { | 
| -    __ LoadTrueFalseRoots(res_true, res_false); | 
| -  } else { | 
| -    // This is counter-intuitive, but correct. | 
| -    __ Mov(res_true, Smi::FromInt(0)); | 
| -    __ Mov(res_false, Smi::FromInt(1)); | 
| -  } | 
| - | 
| -  // Check that the left hand side is a JS object and load its map as a side | 
| -  // effect. | 
| -  Register map = x12; | 
| -  __ JumpIfSmi(object, ¬_js_object); | 
| -  __ IsObjectJSObjectType(object, map, scratch2, ¬_js_object); | 
| - | 
| -  // If there is a call site cache, don't look in the global cache, but do the | 
| -  // real lookup and update the call site cache. | 
| -  if (!HasCallSiteInlineCheck() && !ReturnTrueFalseObject()) { | 
| -    Label miss; | 
| -    __ JumpIfNotRoot(function, Heap::kInstanceofCacheFunctionRootIndex, &miss); | 
| -    __ JumpIfNotRoot(map, Heap::kInstanceofCacheMapRootIndex, &miss); | 
| -    __ LoadRoot(result, Heap::kInstanceofCacheAnswerRootIndex); | 
| -    __ Ret(); | 
| -    __ Bind(&miss); | 
| -  } | 
| - | 
| -  // Get the prototype of the function. | 
| -  Register prototype = x13; | 
| -  __ TryGetFunctionPrototype(function, prototype, scratch2, &slow, | 
| -                             MacroAssembler::kMissOnBoundFunction); | 
| - | 
| -  // Check that the function prototype is a JS object. | 
| -  __ JumpIfSmi(prototype, &slow); | 
| -  __ IsObjectJSObjectType(prototype, scratch1, scratch2, &slow); | 
| - | 
| -  // Update the global instanceof or call site inlined cache with the current | 
| -  // map and function. The cached answer will be set when it is known below. | 
| -  if (HasCallSiteInlineCheck()) { | 
| -    // Patch the (relocated) inlined map check. | 
| -    __ GetRelocatedValueLocation(map_check_site, scratch1); | 
| -    // We have a cell, so need another level of dereferencing. | 
| -    __ Ldr(scratch1, MemOperand(scratch1)); | 
| -    __ Str(map, FieldMemOperand(scratch1, Cell::kValueOffset)); | 
| - | 
| -    __ Mov(x14, map); | 
| -    // |scratch1| points at the beginning of the cell. Calculate the | 
| -    // field containing the map. | 
| -    __ Add(function, scratch1, Operand(Cell::kValueOffset - 1)); | 
| -    __ RecordWriteField(scratch1, Cell::kValueOffset, x14, function, | 
| -                        kLRHasNotBeenSaved, kDontSaveFPRegs, | 
| -                        OMIT_REMEMBERED_SET, OMIT_SMI_CHECK); | 
| -  } else { | 
| -    __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex); | 
| -    __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex); | 
| -  } | 
| - | 
| -  Label return_true, return_result; | 
| -  Register smi_value = scratch1; | 
| -  { | 
| -    // Loop through the prototype chain looking for the function prototype. | 
| -    Register chain_map = x1; | 
| -    Register chain_prototype = x14; | 
| -    Register null_value = x15; | 
| -    Label loop; | 
| -    __ Ldr(chain_prototype, FieldMemOperand(map, Map::kPrototypeOffset)); | 
| -    __ LoadRoot(null_value, Heap::kNullValueRootIndex); | 
| -    // Speculatively set a result. | 
| -    __ Mov(result, res_false); | 
| -    if (!HasCallSiteInlineCheck() && ReturnTrueFalseObject()) { | 
| -      // Value to store in the cache cannot be an object. | 
| -      __ Mov(smi_value, Smi::FromInt(1)); | 
| -    } | 
| - | 
| -    __ Bind(&loop); | 
| - | 
| -    // If the chain prototype is the object prototype, return true. | 
| -    __ Cmp(chain_prototype, prototype); | 
| -    __ B(eq, &return_true); | 
| - | 
| -    // If the chain prototype is null, we've reached the end of the chain, so | 
| -    // return false. | 
| -    __ Cmp(chain_prototype, null_value); | 
| -    __ B(eq, &return_result); | 
| - | 
| -    // Otherwise, load the next prototype in the chain, and loop. | 
| -    __ Ldr(chain_map, FieldMemOperand(chain_prototype, HeapObject::kMapOffset)); | 
| -    __ Ldr(chain_prototype, FieldMemOperand(chain_map, Map::kPrototypeOffset)); | 
| -    __ B(&loop); | 
| -  } | 
| - | 
| -  // Return sequence when no arguments are on the stack. | 
| -  // We cannot fall through to here. | 
| -  __ Bind(&return_true); | 
| -  __ Mov(result, res_true); | 
| -  if (!HasCallSiteInlineCheck() && ReturnTrueFalseObject()) { | 
| -    // Value to store in the cache cannot be an object. | 
| -    __ Mov(smi_value, Smi::FromInt(0)); | 
| -  } | 
| -  __ Bind(&return_result); | 
| -  if (HasCallSiteInlineCheck()) { | 
| -    DCHECK(ReturnTrueFalseObject()); | 
| -    __ Add(map_check_site, map_check_site, kDeltaToLoadBoolResult); | 
| -    __ GetRelocatedValueLocation(map_check_site, scratch2); | 
| -    __ Str(result, MemOperand(scratch2)); | 
| -  } else { | 
| -    Register cached_value = ReturnTrueFalseObject() ? smi_value : result; | 
| -    __ StoreRoot(cached_value, Heap::kInstanceofCacheAnswerRootIndex); | 
| -  } | 
| +void InstanceOfStub::Generate(MacroAssembler* masm) { | 
| +  Register const object = x1;              // Object (lhs). | 
| +  Register const function = x0;            // Function (rhs). | 
| +  Register const object_map = x2;          // Map of {object}. | 
| +  Register const function_map = x3;        // Map of {function}. | 
| +  Register const function_prototype = x4;  // Prototype of {function}. | 
| +  Register const scratch = x5; | 
| + | 
| +  DCHECK(object.is(InstanceOfDescriptor::LeftRegister())); | 
| +  DCHECK(function.is(InstanceOfDescriptor::RightRegister())); | 
| + | 
| +  // Check if {object} is a smi. | 
| +  Label object_is_smi; | 
| +  __ JumpIfSmi(object, &object_is_smi); | 
| + | 
| +  // Lookup the {function} and the {object} map in the global instanceof cache. | 
| +  // Note: This is safe because we clear the global instanceof cache whenever | 
| +  // we change the prototype of any object. | 
| +  Label fast_case, slow_case; | 
| +  __ Ldr(object_map, FieldMemOperand(object, HeapObject::kMapOffset)); | 
| +  __ JumpIfNotRoot(function, Heap::kInstanceofCacheFunctionRootIndex, | 
| +                   &fast_case); | 
| +  __ JumpIfNotRoot(object_map, Heap::kInstanceofCacheMapRootIndex, &fast_case); | 
| +  __ LoadRoot(x0, Heap::kInstanceofCacheAnswerRootIndex); | 
| __ Ret(); | 
|  | 
| -  Label object_not_null, object_not_null_or_smi; | 
| - | 
| -  __ Bind(¬_js_object); | 
| -  Register object_type = x14; | 
| -  //   x0   result        result return register (uninit) | 
| -  //   x10  function      pointer to function | 
| -  //   x11  object        pointer to object | 
| -  //   x14  object_type   type of object (uninit) | 
| - | 
| -  // Before null, smi and string checks, check that the rhs is a function. | 
| -  // For a non-function rhs, an exception must be thrown. | 
| -  __ JumpIfSmi(function, &slow); | 
| -  __ JumpIfNotObjectType( | 
| -      function, scratch1, object_type, JS_FUNCTION_TYPE, &slow); | 
| - | 
| -  __ Mov(result, res_false); | 
| - | 
| -  // Null is not instance of anything. | 
| -  __ Cmp(object, Operand(isolate()->factory()->null_value())); | 
| -  __ B(ne, &object_not_null); | 
| +  // If {object} is a smi we can safely return false if {function} is a JS | 
| +  // function, otherwise we have to miss to the runtime and throw an exception. | 
| +  __ Bind(&object_is_smi); | 
| +  __ JumpIfSmi(function, &slow_case); | 
| +  __ JumpIfNotObjectType(function, function_map, scratch, JS_FUNCTION_TYPE, | 
| +                         &slow_case); | 
| +  __ LoadRoot(x0, Heap::kFalseValueRootIndex); | 
| __ Ret(); | 
|  | 
| -  __ Bind(&object_not_null); | 
| -  // Smi values are not instances of anything. | 
| -  __ JumpIfNotSmi(object, &object_not_null_or_smi); | 
| -  __ Ret(); | 
| +  // Fast-case: The {function} must be a valid JSFunction. | 
| +  __ Bind(&fast_case); | 
| +  __ JumpIfSmi(function, &slow_case); | 
| +  __ JumpIfNotObjectType(function, function_map, scratch, JS_FUNCTION_TYPE, | 
| +                         &slow_case); | 
|  | 
| -  __ Bind(&object_not_null_or_smi); | 
| -  // String values are not instances of anything. | 
| -  __ IsObjectJSStringType(object, scratch2, &slow); | 
| -  __ Ret(); | 
| +  // Ensure that {function} has an instance prototype. | 
| +  __ Ldrb(scratch, FieldMemOperand(function_map, Map::kBitFieldOffset)); | 
| +  __ Tbnz(scratch, Map::kHasNonInstancePrototype, &slow_case); | 
|  | 
| -  // Slow-case. Tail call builtin. | 
| -  __ Bind(&slow); | 
| -  { | 
| -    FrameScope scope(masm, StackFrame::INTERNAL); | 
| -    // Arguments have either been passed into registers or have been previously | 
| -    // popped. We need to push them before calling builtin. | 
| -    __ Push(object, function); | 
| -    __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION); | 
| -  } | 
| -  if (ReturnTrueFalseObject()) { | 
| -    // Reload true/false because they were clobbered in the builtin call. | 
| -    __ LoadTrueFalseRoots(res_true, res_false); | 
| -    __ Cmp(result, 0); | 
| -    __ Csel(result, res_true, res_false, eq); | 
| -  } | 
| +  // Ensure that {function} is not bound. | 
| +  Register const shared_info = scratch; | 
| +  Register const scratch_w = scratch.W(); | 
| +  __ Ldr(shared_info, | 
| +         FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset)); | 
| +  // On 64-bit platforms, compiler hints field is not a smi. See definition of | 
| +  // kCompilerHintsOffset in src/objects.h. | 
| +  __ Ldr(scratch_w, FieldMemOperand(shared_info, | 
| +                                    SharedFunctionInfo::kCompilerHintsOffset)); | 
| +  __ Tbnz(scratch_w, SharedFunctionInfo::kBoundFunction, &slow_case); | 
| + | 
| +  // Get the "prototype" (or initial map) of the {function}. | 
| +  __ Ldr(function_prototype, | 
| +         FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); | 
| +  __ AssertNotSmi(function_prototype); | 
| + | 
| +  // Resolve the prototype if the {function} has an initial map.  Afterwards the | 
| +  // {function_prototype} will be either the JSReceiver prototype object or the | 
| +  // hole value, which means that no instances of the {function} were created so | 
| +  // far and hence we should return false. | 
| +  Label function_prototype_valid; | 
| +  __ JumpIfNotObjectType(function_prototype, scratch, scratch, MAP_TYPE, | 
| +                         &function_prototype_valid); | 
| +  __ Ldr(function_prototype, | 
| +         FieldMemOperand(function_prototype, Map::kPrototypeOffset)); | 
| +  __ Bind(&function_prototype_valid); | 
| +  __ AssertNotSmi(function_prototype); | 
| + | 
| +  // Update the global instanceof cache with the current {object} map and | 
| +  // {function}.  The cached answer will be set when it is known below. | 
| +  __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex); | 
| +  __ StoreRoot(object_map, Heap::kInstanceofCacheMapRootIndex); | 
| + | 
| +  // Loop through the prototype chain looking for the {function} prototype. | 
| +  // Assume true, and change to false if not found. | 
| +  Register const object_prototype = object_map; | 
| +  Register const null = scratch; | 
| +  Label done, loop; | 
| +  __ LoadRoot(x0, Heap::kTrueValueRootIndex); | 
| +  __ LoadRoot(null, Heap::kNullValueRootIndex); | 
| +  __ Bind(&loop); | 
| +  __ Ldr(object_prototype, FieldMemOperand(object_map, Map::kPrototypeOffset)); | 
| +  __ Cmp(object_prototype, function_prototype); | 
| +  __ B(eq, &done); | 
| +  __ Cmp(object_prototype, null); | 
| +  __ Ldr(object_map, FieldMemOperand(object_prototype, HeapObject::kMapOffset)); | 
| +  __ B(ne, &loop); | 
| +  __ LoadRoot(x0, Heap::kFalseValueRootIndex); | 
| +  __ Bind(&done); | 
| +  __ StoreRoot(x0, Heap::kInstanceofCacheAnswerRootIndex); | 
| __ Ret(); | 
| + | 
| +  // Slow-case: Call the runtime function. | 
| +  __ bind(&slow_case); | 
| +  __ Push(object, function); | 
| +  __ TailCallRuntime(Runtime::kInstanceOf, 2, 1); | 
| } | 
|  | 
|  | 
|  |