Commit 529e3332 authored by zhengxing.li's avatar zhengxing.li Committed by Commit bot

X87: [es6] Reintroduce the instanceof operator in the backends.

  port 551e0aa1 (r36275)

  original commit message:
  This adds back the instanceof operator support in the backends and
  introduces a @@hasInstance protector cell on the isolate that guards the
  fast path for the InstanceOfStub. This way we recover the ~10%
  regression on Octane EarleyBoyer in Crankshaft and greatly improve
  TurboFan and Ignition performance of instanceof.

BUG=

Review-Url: https://codereview.chromium.org/1991663002
Cr-Commit-Position: refs/heads/master@{#36303}
parent 33e571ff
......@@ -2575,16 +2575,6 @@ void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
}
void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
DCHECK(ToRegister(instr->context()).is(esi));
DCHECK(ToRegister(instr->left()).is(InstanceOfDescriptor::LeftRegister()));
DCHECK(ToRegister(instr->right()).is(InstanceOfDescriptor::RightRegister()));
DCHECK(ToRegister(instr->result()).is(eax));
InstanceOfStub stub(isolate());
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
}
void LCodeGen::DoHasInPrototypeChainAndBranch(
LHasInPrototypeChainAndBranch* instr) {
Register const object = ToRegister(instr->object());
......
......@@ -983,17 +983,6 @@ LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
}
LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
LOperand* left =
UseFixed(instr->left(), InstanceOfDescriptor::LeftRegister());
LOperand* right =
UseFixed(instr->right(), InstanceOfDescriptor::RightRegister());
LOperand* context = UseFixed(instr->context(), esi);
LInstanceOf* result = new (zone()) LInstanceOf(context, left, right);
return MarkAsCall(DefineFixed(result, eax), instr);
}
LInstruction* LChunkBuilder::DoHasInPrototypeChainAndBranch(
HHasInPrototypeChainAndBranch* instr) {
LOperand* object = UseRegister(instr->object());
......
......@@ -84,7 +84,6 @@ class LCodeGen;
V(HasInPrototypeChainAndBranch) \
V(HasInstanceTypeAndBranch) \
V(InnerAllocatedObject) \
V(InstanceOf) \
V(InstructionGap) \
V(Integer32ToDouble) \
V(InvokeFunction) \
......@@ -1134,22 +1133,6 @@ class LCmpT final : public LTemplateInstruction<1, 3, 0> {
};
class LInstanceOf final : public LTemplateInstruction<1, 3, 0> {
public:
LInstanceOf(LOperand* context, LOperand* left, LOperand* right) {
inputs_[0] = context;
inputs_[1] = left;
inputs_[2] = right;
}
LOperand* context() const { return inputs_[0]; }
LOperand* left() const { return inputs_[1]; }
LOperand* right() const { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(InstanceOf, "instance-of")
};
class LHasInPrototypeChainAndBranch final : public LControlInstruction<2, 1> {
public:
LHasInPrototypeChainAndBranch(LOperand* object, LOperand* prototype,
......
......@@ -3021,13 +3021,6 @@ void FullCodeGenerator::EmitGetSuperConstructor(CallRuntime* expr) {
context()->Plug(eax);
}
void FullCodeGenerator::EmitGetOrdinaryHasInstance(CallRuntime* expr) {
DCHECK_EQ(0, expr->arguments()->length());
__ mov(eax, NativeContextOperand());
__ mov(eax, ContextOperand(eax, Context::ORDINARY_HAS_INSTANCE_INDEX));
context()->Plug(eax);
}
void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
DCHECK(expr->arguments()->length() == 0);
ExternalReference debug_is_active =
......
......@@ -1217,29 +1217,6 @@ void Builtins::Generate_DatePrototype_GetField(MacroAssembler* masm,
}
}
// static
void Builtins::Generate_FunctionHasInstance(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : argc
// -- esp[0] : return address
// -- esp[4] : first argument (left-hand side)
// -- esp[8] : receiver (right-hand side)
// -----------------------------------
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ mov(InstanceOfDescriptor::LeftRegister(),
Operand(ebp, 2 * kPointerSize)); // Load left-hand side.
__ mov(InstanceOfDescriptor::RightRegister(),
Operand(ebp, 3 * kPointerSize)); // Load right-hand side.
InstanceOfStub stub(masm->isolate(), true);
__ CallStub(&stub);
}
// Pop the argument and the receiver.
__ ret(2 * kPointerSize);
}
// static
void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
// ----------- S t a t e -------------
......
......@@ -1770,129 +1770,6 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
}
void InstanceOfStub::Generate(MacroAssembler* masm) {
Register const object = edx; // Object (lhs).
Register const function = eax; // Function (rhs).
Register const object_map = ecx; // Map of {object}.
Register const function_map = ebx; // Map of {function}.
Register const function_prototype = function_map; // Prototype of {function}.
Register const scratch = edi;
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, Label::kNear);
// 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;
__ mov(object_map, FieldOperand(object, HeapObject::kMapOffset));
__ CompareRoot(function, scratch, Heap::kInstanceofCacheFunctionRootIndex);
__ j(not_equal, &fast_case, Label::kNear);
__ CompareRoot(object_map, scratch, Heap::kInstanceofCacheMapRootIndex);
__ j(not_equal, &fast_case, Label::kNear);
__ LoadRoot(eax, Heap::kInstanceofCacheAnswerRootIndex);
__ ret(0);
// 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);
__ CmpObjectType(function, JS_FUNCTION_TYPE, function_map);
__ j(not_equal, &slow_case);
__ LoadRoot(eax, Heap::kFalseValueRootIndex);
__ ret(0);
// Fast-case: The {function} must be a valid JSFunction.
__ bind(&fast_case);
__ JumpIfSmi(function, &slow_case);
__ CmpObjectType(function, JS_FUNCTION_TYPE, function_map);
__ j(not_equal, &slow_case);
// Go to the runtime if the function is not a constructor.
__ test_b(FieldOperand(function_map, Map::kBitFieldOffset),
Immediate(1 << Map::kIsConstructor));
__ j(zero, &slow_case);
// Ensure that {function} has an instance prototype.
__ test_b(FieldOperand(function_map, Map::kBitFieldOffset),
Immediate(1 << Map::kHasNonInstancePrototype));
__ j(not_zero, &slow_case);
// Get the "prototype" (or initial map) of the {function}.
__ mov(function_prototype,
FieldOperand(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;
Register const function_prototype_map = scratch;
__ CmpObjectType(function_prototype, MAP_TYPE, function_prototype_map);
__ j(not_equal, &function_prototype_valid, Label::kNear);
__ mov(function_prototype,
FieldOperand(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, scratch, Heap::kInstanceofCacheFunctionRootIndex);
__ StoreRoot(object_map, scratch, Heap::kInstanceofCacheMapRootIndex);
// Loop through the prototype chain looking for the {function} prototype.
// Assume true, and change to false if not found.
Label done, loop, fast_runtime_fallback;
__ mov(eax, isolate()->factory()->true_value());
__ bind(&loop);
// Check if the object needs to be access checked.
__ test_b(FieldOperand(object_map, Map::kBitFieldOffset),
Immediate(1 << Map::kIsAccessCheckNeeded));
__ j(not_zero, &fast_runtime_fallback, Label::kNear);
// Check if the current object is a Proxy.
__ CmpInstanceType(object_map, JS_PROXY_TYPE);
__ j(equal, &fast_runtime_fallback, Label::kNear);
__ mov(object, FieldOperand(object_map, Map::kPrototypeOffset));
__ cmp(object, function_prototype);
__ j(equal, &done, Label::kNear);
__ mov(object_map, FieldOperand(object, HeapObject::kMapOffset));
__ cmp(object, isolate()->factory()->null_value());
__ j(not_equal, &loop);
__ mov(eax, isolate()->factory()->false_value());
__ bind(&done);
__ StoreRoot(eax, scratch, Heap::kInstanceofCacheAnswerRootIndex);
__ ret(0);
// Found Proxy or access check needed: Call the runtime.
__ bind(&fast_runtime_fallback);
__ PopReturnAddressTo(scratch);
__ Push(object);
__ Push(function_prototype);
__ PushReturnAddressFrom(scratch);
// Invalidate the instanceof cache.
__ Move(eax, Immediate(Smi::FromInt(0)));
__ StoreRoot(eax, scratch, Heap::kInstanceofCacheFunctionRootIndex);
__ TailCallRuntime(Runtime::kHasInPrototypeChain);
// Slow-case: Call the %InstanceOf runtime function.
__ bind(&slow_case);
__ PopReturnAddressTo(scratch);
__ Push(object);
__ Push(function);
__ PushReturnAddressFrom(scratch);
__ TailCallRuntime(is_es6_instanceof() ? Runtime::kOrdinaryHasInstance
: Runtime::kInstanceOf);
}
// -------------------------------------------------------------------------
// StringCharCodeAtGenerator
......
......@@ -51,10 +51,6 @@ const Register StoreGlobalViaContextDescriptor::SlotRegister() { return ebx; }
const Register StoreGlobalViaContextDescriptor::ValueRegister() { return eax; }
const Register InstanceOfDescriptor::LeftRegister() { return edx; }
const Register InstanceOfDescriptor::RightRegister() { return eax; }
const Register StringCompareDescriptor::LeftRegister() { return edx; }
const Register StringCompareDescriptor::RightRegister() { return eax; }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment