[strong] Disallow implicit conversions for comparison
Implements the strong mode proposal's restrictions on implicit conversions for the binary >, >=, <, and <= operators. BUG=v8:3956 LOG=N Review URL: https://codereview.chromium.org/1130283002 Cr-Commit-Position: refs/heads/master@{#28370}
This commit is contained in:
parent
188297160d
commit
03ef40b46c
@ -93,9 +93,8 @@ void InternalArrayNArgumentsConstructorStub::InitializeDescriptor(
|
|||||||
#define __ ACCESS_MASM(masm)
|
#define __ ACCESS_MASM(masm)
|
||||||
|
|
||||||
|
|
||||||
static void EmitIdenticalObjectComparison(MacroAssembler* masm,
|
static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow,
|
||||||
Label* slow,
|
Condition cond, bool strong);
|
||||||
Condition cond);
|
|
||||||
static void EmitSmiNonsmiComparison(MacroAssembler* masm,
|
static void EmitSmiNonsmiComparison(MacroAssembler* masm,
|
||||||
Register lhs,
|
Register lhs,
|
||||||
Register rhs,
|
Register rhs,
|
||||||
@ -238,9 +237,8 @@ void DoubleToIStub::Generate(MacroAssembler* masm) {
|
|||||||
// Handle the case where the lhs and rhs are the same object.
|
// Handle the case where the lhs and rhs are the same object.
|
||||||
// Equality is almost reflexive (everything but NaN), so this is a test
|
// Equality is almost reflexive (everything but NaN), so this is a test
|
||||||
// for "identity and not NaN".
|
// for "identity and not NaN".
|
||||||
static void EmitIdenticalObjectComparison(MacroAssembler* masm,
|
static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow,
|
||||||
Label* slow,
|
Condition cond, bool strong) {
|
||||||
Condition cond) {
|
|
||||||
Label not_identical;
|
Label not_identical;
|
||||||
Label heap_number, return_equal;
|
Label heap_number, return_equal;
|
||||||
__ cmp(r0, r1);
|
__ cmp(r0, r1);
|
||||||
@ -251,10 +249,20 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm,
|
|||||||
// They are both equal and they are not both Smis so both of them are not
|
// They are both equal and they are not both Smis so both of them are not
|
||||||
// Smis. If it's not a heap number, then return equal.
|
// Smis. If it's not a heap number, then return equal.
|
||||||
if (cond == lt || cond == gt) {
|
if (cond == lt || cond == gt) {
|
||||||
|
// Call runtime on identical JSObjects.
|
||||||
__ CompareObjectType(r0, r4, r4, FIRST_SPEC_OBJECT_TYPE);
|
__ CompareObjectType(r0, r4, r4, FIRST_SPEC_OBJECT_TYPE);
|
||||||
__ b(ge, slow);
|
__ b(ge, slow);
|
||||||
|
// Call runtime on identical symbols since we need to throw a TypeError.
|
||||||
__ cmp(r4, Operand(SYMBOL_TYPE));
|
__ cmp(r4, Operand(SYMBOL_TYPE));
|
||||||
__ b(eq, slow);
|
__ b(eq, slow);
|
||||||
|
if (strong) {
|
||||||
|
// Call the runtime on anything that is converted in the semantics, since
|
||||||
|
// we need to throw a TypeError. Smis have already been ruled out.
|
||||||
|
__ cmp(r4, Operand(HEAP_NUMBER_TYPE));
|
||||||
|
__ b(eq, &return_equal);
|
||||||
|
__ tst(r4, Operand(kIsNotStringMask));
|
||||||
|
__ b(ne, slow);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
__ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE);
|
__ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE);
|
||||||
__ b(eq, &heap_number);
|
__ b(eq, &heap_number);
|
||||||
@ -262,8 +270,16 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm,
|
|||||||
if (cond != eq) {
|
if (cond != eq) {
|
||||||
__ cmp(r4, Operand(FIRST_SPEC_OBJECT_TYPE));
|
__ cmp(r4, Operand(FIRST_SPEC_OBJECT_TYPE));
|
||||||
__ b(ge, slow);
|
__ b(ge, slow);
|
||||||
|
// Call runtime on identical symbols since we need to throw a TypeError.
|
||||||
__ cmp(r4, Operand(SYMBOL_TYPE));
|
__ cmp(r4, Operand(SYMBOL_TYPE));
|
||||||
__ b(eq, slow);
|
__ b(eq, slow);
|
||||||
|
if (strong) {
|
||||||
|
// Call the runtime on anything that is converted in the semantics,
|
||||||
|
// since we need to throw a TypeError. Smis and heap numbers have
|
||||||
|
// already been ruled out.
|
||||||
|
__ tst(r4, Operand(kIsNotStringMask));
|
||||||
|
__ b(ne, slow);
|
||||||
|
}
|
||||||
// Normally here we fall through to return_equal, but undefined is
|
// Normally here we fall through to return_equal, but undefined is
|
||||||
// special: (undefined == undefined) == true, but
|
// special: (undefined == undefined) == true, but
|
||||||
// (undefined <= undefined) == false! See ECMAScript 11.8.5.
|
// (undefined <= undefined) == false! See ECMAScript 11.8.5.
|
||||||
@ -561,7 +577,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
|
|
||||||
// Handle the case where the objects are identical. Either returns the answer
|
// Handle the case where the objects are identical. Either returns the answer
|
||||||
// or goes to slow. Only falls through if the objects were not identical.
|
// or goes to slow. Only falls through if the objects were not identical.
|
||||||
EmitIdenticalObjectComparison(masm, &slow, cc);
|
EmitIdenticalObjectComparison(masm, &slow, cc, strong());
|
||||||
|
|
||||||
// If either is a Smi (we know that not both are), then they can only
|
// If either is a Smi (we know that not both are), then they can only
|
||||||
// be strictly equal if the other is a HeapNumber.
|
// be strictly equal if the other is a HeapNumber.
|
||||||
@ -663,7 +679,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
if (cc == eq) {
|
if (cc == eq) {
|
||||||
native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
|
native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
|
||||||
} else {
|
} else {
|
||||||
native = Builtins::COMPARE;
|
native = strong() ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
|
||||||
int ncr; // NaN compare result
|
int ncr; // NaN compare result
|
||||||
if (cc == lt || cc == le) {
|
if (cc == lt || cc == le) {
|
||||||
ncr = GREATER;
|
ncr = GREATER;
|
||||||
@ -3567,7 +3583,7 @@ void CompareICStub::GenerateNumbers(MacroAssembler* masm) {
|
|||||||
|
|
||||||
__ bind(&unordered);
|
__ bind(&unordered);
|
||||||
__ bind(&generic_stub);
|
__ bind(&generic_stub);
|
||||||
CompareICStub stub(isolate(), op(), CompareICState::GENERIC,
|
CompareICStub stub(isolate(), op(), strong(), CompareICState::GENERIC,
|
||||||
CompareICState::GENERIC, CompareICState::GENERIC);
|
CompareICState::GENERIC, CompareICState::GENERIC);
|
||||||
__ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
|
__ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
|
||||||
|
|
||||||
|
@ -1059,8 +1059,8 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
|
|||||||
|
|
||||||
// Record position before stub call for type feedback.
|
// Record position before stub call for type feedback.
|
||||||
SetSourcePosition(clause->position());
|
SetSourcePosition(clause->position());
|
||||||
Handle<Code> ic =
|
Handle<Code> ic = CodeFactory::CompareIC(isolate(), Token::EQ_STRICT,
|
||||||
CodeFactory::CompareIC(isolate(), Token::EQ_STRICT).code();
|
language_mode()).code();
|
||||||
CallIC(ic, clause->CompareId());
|
CallIC(ic, clause->CompareId());
|
||||||
patch_site.EmitPatchInfo();
|
patch_site.EmitPatchInfo();
|
||||||
|
|
||||||
@ -5238,7 +5238,8 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
|
|||||||
|
|
||||||
// Record position and call the compare IC.
|
// Record position and call the compare IC.
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position());
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic =
|
||||||
|
CodeFactory::CompareIC(isolate(), op, language_mode()).code();
|
||||||
CallIC(ic, expr->CompareOperationFeedbackId());
|
CallIC(ic, expr->CompareOperationFeedbackId());
|
||||||
patch_site.EmitPatchInfo();
|
patch_site.EmitPatchInfo();
|
||||||
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
|
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
|
||||||
|
@ -1197,6 +1197,8 @@ class LCmpT final : public LTemplateInstruction<1, 3, 0> {
|
|||||||
DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
|
DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
|
||||||
DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
|
DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
|
||||||
|
|
||||||
|
LanguageMode language_mode() { return hydrogen()->language_mode(); }
|
||||||
|
|
||||||
Token::Value op() const { return hydrogen()->token(); }
|
Token::Value op() const { return hydrogen()->token(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2612,7 +2612,7 @@ void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
|
|||||||
DCHECK(ToRegister(instr->context()).is(cp));
|
DCHECK(ToRegister(instr->context()).is(cp));
|
||||||
Token::Value op = instr->op();
|
Token::Value op = instr->op();
|
||||||
|
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op, SLOPPY).code();
|
||||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||||
// This instruction also signals no smi code inlined.
|
// This instruction also signals no smi code inlined.
|
||||||
__ cmp(r0, Operand::Zero());
|
__ cmp(r0, Operand::Zero());
|
||||||
@ -2929,7 +2929,8 @@ void LCodeGen::DoCmpT(LCmpT* instr) {
|
|||||||
DCHECK(ToRegister(instr->context()).is(cp));
|
DCHECK(ToRegister(instr->context()).is(cp));
|
||||||
Token::Value op = instr->op();
|
Token::Value op = instr->op();
|
||||||
|
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic =
|
||||||
|
CodeFactory::CompareIC(isolate(), op, instr->language_mode()).code();
|
||||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||||
// This instruction also signals no smi code inlined.
|
// This instruction also signals no smi code inlined.
|
||||||
__ cmp(r0, Operand::Zero());
|
__ cmp(r0, Operand::Zero());
|
||||||
|
@ -203,13 +203,11 @@ void DoubleToIStub::Generate(MacroAssembler* masm) {
|
|||||||
|
|
||||||
|
|
||||||
// See call site for description.
|
// See call site for description.
|
||||||
static void EmitIdenticalObjectComparison(MacroAssembler* masm,
|
static void EmitIdenticalObjectComparison(MacroAssembler* masm, Register left,
|
||||||
Register left,
|
Register right, Register scratch,
|
||||||
Register right,
|
|
||||||
Register scratch,
|
|
||||||
FPRegister double_scratch,
|
FPRegister double_scratch,
|
||||||
Label* slow,
|
Label* slow, Condition cond,
|
||||||
Condition cond) {
|
bool strong) {
|
||||||
DCHECK(!AreAliased(left, right, scratch));
|
DCHECK(!AreAliased(left, right, scratch));
|
||||||
Label not_identical, return_equal, heap_number;
|
Label not_identical, return_equal, heap_number;
|
||||||
Register result = x0;
|
Register result = x0;
|
||||||
@ -223,10 +221,20 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm,
|
|||||||
// Smis. If it's not a heap number, then return equal.
|
// Smis. If it's not a heap number, then return equal.
|
||||||
Register right_type = scratch;
|
Register right_type = scratch;
|
||||||
if ((cond == lt) || (cond == gt)) {
|
if ((cond == lt) || (cond == gt)) {
|
||||||
|
// Call runtime on identical JSObjects. Otherwise return equal.
|
||||||
__ JumpIfObjectType(right, right_type, right_type, FIRST_SPEC_OBJECT_TYPE,
|
__ JumpIfObjectType(right, right_type, right_type, FIRST_SPEC_OBJECT_TYPE,
|
||||||
slow, ge);
|
slow, ge);
|
||||||
|
// Call runtime on identical symbols since we need to throw a TypeError.
|
||||||
__ Cmp(right_type, SYMBOL_TYPE);
|
__ Cmp(right_type, SYMBOL_TYPE);
|
||||||
__ B(eq, slow);
|
__ B(eq, slow);
|
||||||
|
if (strong) {
|
||||||
|
// Call the runtime on anything that is converted in the semantics, since
|
||||||
|
// we need to throw a TypeError. Smis have already been ruled out.
|
||||||
|
__ Cmp(right_type, Operand(HEAP_NUMBER_TYPE));
|
||||||
|
__ B(eq, &return_equal);
|
||||||
|
__ Tst(right_type, Operand(kIsNotStringMask));
|
||||||
|
__ B(ne, slow);
|
||||||
|
}
|
||||||
} else if (cond == eq) {
|
} else if (cond == eq) {
|
||||||
__ JumpIfHeapNumber(right, &heap_number);
|
__ JumpIfHeapNumber(right, &heap_number);
|
||||||
} else {
|
} else {
|
||||||
@ -235,8 +243,16 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm,
|
|||||||
// Comparing JS objects with <=, >= is complicated.
|
// Comparing JS objects with <=, >= is complicated.
|
||||||
__ Cmp(right_type, FIRST_SPEC_OBJECT_TYPE);
|
__ Cmp(right_type, FIRST_SPEC_OBJECT_TYPE);
|
||||||
__ B(ge, slow);
|
__ B(ge, slow);
|
||||||
|
// Call runtime on identical symbols since we need to throw a TypeError.
|
||||||
__ Cmp(right_type, SYMBOL_TYPE);
|
__ Cmp(right_type, SYMBOL_TYPE);
|
||||||
__ B(eq, slow);
|
__ B(eq, slow);
|
||||||
|
if (strong) {
|
||||||
|
// Call the runtime on anything that is converted in the semantics,
|
||||||
|
// since we need to throw a TypeError. Smis and heap numbers have
|
||||||
|
// already been ruled out.
|
||||||
|
__ Tst(right_type, Operand(kIsNotStringMask));
|
||||||
|
__ B(ne, slow);
|
||||||
|
}
|
||||||
// Normally here we fall through to return_equal, but undefined is
|
// Normally here we fall through to return_equal, but undefined is
|
||||||
// special: (undefined == undefined) == true, but
|
// special: (undefined == undefined) == true, but
|
||||||
// (undefined <= undefined) == false! See ECMAScript 11.8.5.
|
// (undefined <= undefined) == false! See ECMAScript 11.8.5.
|
||||||
@ -513,7 +529,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
|
|
||||||
// Handle the case where the objects are identical. Either returns the answer
|
// Handle the case where the objects are identical. Either returns the answer
|
||||||
// or goes to slow. Only falls through if the objects were not identical.
|
// or goes to slow. Only falls through if the objects were not identical.
|
||||||
EmitIdenticalObjectComparison(masm, lhs, rhs, x10, d0, &slow, cond);
|
EmitIdenticalObjectComparison(masm, lhs, rhs, x10, d0, &slow, cond, strong());
|
||||||
|
|
||||||
// If either is a smi (we know that at least one is not a smi), then they can
|
// If either is a smi (we know that at least one is not a smi), then they can
|
||||||
// only be strictly equal if the other is a HeapNumber.
|
// only be strictly equal if the other is a HeapNumber.
|
||||||
@ -632,7 +648,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
if (cond == eq) {
|
if (cond == eq) {
|
||||||
native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
|
native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
|
||||||
} else {
|
} else {
|
||||||
native = Builtins::COMPARE;
|
native = strong() ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
|
||||||
int ncr; // NaN compare result
|
int ncr; // NaN compare result
|
||||||
if ((cond == lt) || (cond == le)) {
|
if ((cond == lt) || (cond == le)) {
|
||||||
ncr = GREATER;
|
ncr = GREATER;
|
||||||
@ -3485,7 +3501,7 @@ void CompareICStub::GenerateNumbers(MacroAssembler* masm) {
|
|||||||
__ Ret();
|
__ Ret();
|
||||||
|
|
||||||
__ Bind(&unordered);
|
__ Bind(&unordered);
|
||||||
CompareICStub stub(isolate(), op(), CompareICState::GENERIC,
|
CompareICStub stub(isolate(), op(), strong(), CompareICState::GENERIC,
|
||||||
CompareICState::GENERIC, CompareICState::GENERIC);
|
CompareICState::GENERIC, CompareICState::GENERIC);
|
||||||
__ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
|
__ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
|
||||||
|
|
||||||
|
@ -1058,8 +1058,8 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
|
|||||||
|
|
||||||
// Record position before stub call for type feedback.
|
// Record position before stub call for type feedback.
|
||||||
SetSourcePosition(clause->position());
|
SetSourcePosition(clause->position());
|
||||||
Handle<Code> ic =
|
Handle<Code> ic = CodeFactory::CompareIC(isolate(), Token::EQ_STRICT,
|
||||||
CodeFactory::CompareIC(isolate(), Token::EQ_STRICT).code();
|
language_mode()).code();
|
||||||
CallIC(ic, clause->CompareId());
|
CallIC(ic, clause->CompareId());
|
||||||
patch_site.EmitPatchInfo();
|
patch_site.EmitPatchInfo();
|
||||||
|
|
||||||
@ -4925,7 +4925,8 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
|
|||||||
|
|
||||||
// Record position and call the compare IC.
|
// Record position and call the compare IC.
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position());
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic =
|
||||||
|
CodeFactory::CompareIC(isolate(), op, language_mode()).code();
|
||||||
CallIC(ic, expr->CompareOperationFeedbackId());
|
CallIC(ic, expr->CompareOperationFeedbackId());
|
||||||
patch_site.EmitPatchInfo();
|
patch_site.EmitPatchInfo();
|
||||||
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
|
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
|
||||||
|
@ -1182,6 +1182,8 @@ class LCmpT final : public LTemplateInstruction<1, 3, 0> {
|
|||||||
DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
|
DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
|
||||||
DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
|
DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
|
||||||
|
|
||||||
|
LanguageMode language_mode() { return hydrogen()->language_mode(); }
|
||||||
|
|
||||||
Token::Value op() const { return hydrogen()->token(); }
|
Token::Value op() const { return hydrogen()->token(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2555,7 +2555,8 @@ void LCodeGen::DoCmpT(LCmpT* instr) {
|
|||||||
|
|
||||||
DCHECK(ToRegister(instr->left()).Is(x1));
|
DCHECK(ToRegister(instr->left()).Is(x1));
|
||||||
DCHECK(ToRegister(instr->right()).Is(x0));
|
DCHECK(ToRegister(instr->right()).Is(x0));
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic =
|
||||||
|
CodeFactory::CompareIC(isolate(), op, instr->language_mode()).code();
|
||||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||||
// Signal that we don't inline smi code before this stub.
|
// Signal that we don't inline smi code before this stub.
|
||||||
InlineSmiCheckInfo::EmitNotInlined(masm());
|
InlineSmiCheckInfo::EmitNotInlined(masm());
|
||||||
@ -5634,7 +5635,7 @@ void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
|
|||||||
DCHECK(ToRegister(instr->context()).is(cp));
|
DCHECK(ToRegister(instr->context()).is(cp));
|
||||||
Token::Value op = instr->op();
|
Token::Value op = instr->op();
|
||||||
|
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op, SLOPPY).code();
|
||||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||||
InlineSmiCheckInfo::EmitNotInlined(masm());
|
InlineSmiCheckInfo::EmitNotInlined(masm());
|
||||||
|
|
||||||
|
@ -171,6 +171,7 @@ enum BuiltinExtraArguments {
|
|||||||
V(EQUALS, 1) \
|
V(EQUALS, 1) \
|
||||||
V(STRICT_EQUALS, 1) \
|
V(STRICT_EQUALS, 1) \
|
||||||
V(COMPARE, 2) \
|
V(COMPARE, 2) \
|
||||||
|
V(COMPARE_STRONG, 2) \
|
||||||
V(ADD, 1) \
|
V(ADD, 1) \
|
||||||
V(ADD_STRONG, 1) \
|
V(ADD_STRONG, 1) \
|
||||||
V(SUB, 1) \
|
V(SUB, 1) \
|
||||||
|
@ -105,8 +105,10 @@ Callable CodeFactory::KeyedStoreICInOptimizedCode(
|
|||||||
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
Callable CodeFactory::CompareIC(Isolate* isolate, Token::Value op) {
|
Callable CodeFactory::CompareIC(Isolate* isolate, Token::Value op,
|
||||||
Handle<Code> code = CompareIC::GetUninitialized(isolate, op);
|
LanguageMode language_mode) {
|
||||||
|
Handle<Code> code =
|
||||||
|
CompareIC::GetUninitialized(isolate, op, is_strong(language_mode));
|
||||||
return Callable(code, CompareDescriptor(isolate));
|
return Callable(code, CompareDescriptor(isolate));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,8 @@ class CodeFactory final {
|
|||||||
Isolate* isolate, LanguageMode mode,
|
Isolate* isolate, LanguageMode mode,
|
||||||
InlineCacheState initialization_state);
|
InlineCacheState initialization_state);
|
||||||
|
|
||||||
static Callable CompareIC(Isolate* isolate, Token::Value op);
|
static Callable CompareIC(Isolate* isolate, Token::Value op,
|
||||||
|
LanguageMode language_mode);
|
||||||
|
|
||||||
static Callable BinaryOpIC(Isolate* isolate, Token::Value op,
|
static Callable BinaryOpIC(Isolate* isolate, Token::Value op,
|
||||||
LanguageMode language_mode);
|
LanguageMode language_mode);
|
||||||
|
@ -1523,12 +1523,14 @@ class StringAddStub final : public HydrogenCodeStub {
|
|||||||
|
|
||||||
class CompareICStub : public PlatformCodeStub {
|
class CompareICStub : public PlatformCodeStub {
|
||||||
public:
|
public:
|
||||||
CompareICStub(Isolate* isolate, Token::Value op, CompareICState::State left,
|
CompareICStub(Isolate* isolate, Token::Value op, bool strong,
|
||||||
CompareICState::State right, CompareICState::State state)
|
CompareICState::State left, CompareICState::State right,
|
||||||
|
CompareICState::State state)
|
||||||
: PlatformCodeStub(isolate) {
|
: PlatformCodeStub(isolate) {
|
||||||
DCHECK(Token::IsCompareOp(op));
|
DCHECK(Token::IsCompareOp(op));
|
||||||
minor_key_ = OpBits::encode(op - Token::EQ) | LeftStateBits::encode(left) |
|
minor_key_ = OpBits::encode(op - Token::EQ) | StrongBits::encode(strong) |
|
||||||
RightStateBits::encode(right) | StateBits::encode(state);
|
LeftStateBits::encode(left) | RightStateBits::encode(right) |
|
||||||
|
StateBits::encode(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_known_map(Handle<Map> map) { known_map_ = map; }
|
void set_known_map(Handle<Map> map) { known_map_ = map; }
|
||||||
@ -1539,6 +1541,8 @@ class CompareICStub : public PlatformCodeStub {
|
|||||||
return static_cast<Token::Value>(Token::EQ + OpBits::decode(minor_key_));
|
return static_cast<Token::Value>(Token::EQ + OpBits::decode(minor_key_));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool strong() const { return StrongBits::decode(minor_key_); }
|
||||||
|
|
||||||
CompareICState::State left() const {
|
CompareICState::State left() const {
|
||||||
return LeftStateBits::decode(minor_key_);
|
return LeftStateBits::decode(minor_key_);
|
||||||
}
|
}
|
||||||
@ -1570,9 +1574,10 @@ class CompareICStub : public PlatformCodeStub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class OpBits : public BitField<int, 0, 3> {};
|
class OpBits : public BitField<int, 0, 3> {};
|
||||||
class LeftStateBits : public BitField<CompareICState::State, 3, 4> {};
|
class StrongBits : public BitField<bool, 3, 1> {};
|
||||||
class RightStateBits : public BitField<CompareICState::State, 7, 4> {};
|
class LeftStateBits : public BitField<CompareICState::State, 4, 4> {};
|
||||||
class StateBits : public BitField<CompareICState::State, 11, 4> {};
|
class RightStateBits : public BitField<CompareICState::State, 8, 4> {};
|
||||||
|
class StateBits : public BitField<CompareICState::State, 12, 4> {};
|
||||||
|
|
||||||
Handle<Map> known_map_;
|
Handle<Map> known_map_;
|
||||||
|
|
||||||
|
@ -116,7 +116,8 @@ static CallDescriptor::Flags FlagsForNode(Node* node) {
|
|||||||
|
|
||||||
|
|
||||||
void JSGenericLowering::ReplaceWithCompareIC(Node* node, Token::Value token) {
|
void JSGenericLowering::ReplaceWithCompareIC(Node* node, Token::Value token) {
|
||||||
Callable callable = CodeFactory::CompareIC(isolate(), token);
|
Callable callable =
|
||||||
|
CodeFactory::CompareIC(isolate(), token, OpParameter<LanguageMode>(node));
|
||||||
CallDescriptor* desc_compare = Linkage::GetStubCallDescriptor(
|
CallDescriptor* desc_compare = Linkage::GetStubCallDescriptor(
|
||||||
isolate(), zone(), callable.descriptor(), 0,
|
isolate(), zone(), callable.descriptor(), 0,
|
||||||
CallDescriptor::kPatchableCallSiteWithNop | FlagsForNode(node),
|
CallDescriptor::kPatchableCallSiteWithNop | FlagsForNode(node),
|
||||||
|
@ -470,6 +470,9 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
|
|||||||
}
|
}
|
||||||
return r.ChangeToPureOperator(stringOp);
|
return r.ChangeToPureOperator(stringOp);
|
||||||
}
|
}
|
||||||
|
if (r.IsStrong() && !r.BothInputsAre(Type::Number())) {
|
||||||
|
return NoChange();
|
||||||
|
}
|
||||||
#if 0
|
#if 0
|
||||||
// TODO(turbofan): General ToNumber disabled for now because:
|
// TODO(turbofan): General ToNumber disabled for now because:
|
||||||
// a) The inserted ToNumber operation screws up observability of valueOf.
|
// a) The inserted ToNumber operation screws up observability of valueOf.
|
||||||
|
@ -11201,7 +11201,8 @@ HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction(
|
|||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
if (combined_rep.IsTagged() || combined_rep.IsNone()) {
|
if (combined_rep.IsTagged() || combined_rep.IsNone()) {
|
||||||
HCompareGeneric* result = Add<HCompareGeneric>(left, right, op);
|
HCompareGeneric* result =
|
||||||
|
Add<HCompareGeneric>(left, right, op, function_language_mode());
|
||||||
result->set_observed_input_representation(1, left_rep);
|
result->set_observed_input_representation(1, left_rep);
|
||||||
result->set_observed_input_representation(2, right_rep);
|
result->set_observed_input_representation(2, right_rep);
|
||||||
if (result->HasObservableSideEffects()) {
|
if (result->HasObservableSideEffects()) {
|
||||||
|
@ -1666,7 +1666,7 @@ static void BranchIfNotInternalizedString(MacroAssembler* masm,
|
|||||||
|
|
||||||
|
|
||||||
void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
||||||
Label check_unequal_objects;
|
Label runtime_call, check_unequal_objects;
|
||||||
Condition cc = GetCondition();
|
Condition cc = GetCondition();
|
||||||
|
|
||||||
Label miss;
|
Label miss;
|
||||||
@ -1700,13 +1700,18 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
if (cc != equal) {
|
if (cc != equal) {
|
||||||
// Check for undefined. undefined OP undefined is false even though
|
// Check for undefined. undefined OP undefined is false even though
|
||||||
// undefined == undefined.
|
// undefined == undefined.
|
||||||
Label check_for_nan;
|
|
||||||
__ cmp(edx, isolate()->factory()->undefined_value());
|
__ cmp(edx, isolate()->factory()->undefined_value());
|
||||||
|
if (strong()) {
|
||||||
|
// In strong mode, this comparison must throw, so call the runtime.
|
||||||
|
__ j(equal, &runtime_call, Label::kFar);
|
||||||
|
} else {
|
||||||
|
Label check_for_nan;
|
||||||
__ j(not_equal, &check_for_nan, Label::kNear);
|
__ j(not_equal, &check_for_nan, Label::kNear);
|
||||||
__ Move(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
|
__ Move(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
|
||||||
__ ret(0);
|
__ ret(0);
|
||||||
__ bind(&check_for_nan);
|
__ bind(&check_for_nan);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Test for NaN. Compare heap numbers in a general way,
|
// Test for NaN. Compare heap numbers in a general way,
|
||||||
// to hanlde NaNs correctly.
|
// to hanlde NaNs correctly.
|
||||||
@ -1714,12 +1719,20 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
Immediate(isolate()->factory()->heap_number_map()));
|
Immediate(isolate()->factory()->heap_number_map()));
|
||||||
__ j(equal, &generic_heap_number_comparison, Label::kNear);
|
__ j(equal, &generic_heap_number_comparison, Label::kNear);
|
||||||
if (cc != equal) {
|
if (cc != equal) {
|
||||||
|
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
|
||||||
|
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
|
||||||
// Call runtime on identical JSObjects. Otherwise return equal.
|
// Call runtime on identical JSObjects. Otherwise return equal.
|
||||||
__ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
|
__ cmpb(ecx, static_cast<uint8_t>(FIRST_SPEC_OBJECT_TYPE));
|
||||||
__ j(above_equal, ¬_identical);
|
__ j(above_equal, &runtime_call, Label::kFar);
|
||||||
// Call runtime on identical symbols since we need to throw a TypeError.
|
// Call runtime on identical symbols since we need to throw a TypeError.
|
||||||
__ CmpObjectType(eax, SYMBOL_TYPE, ecx);
|
__ cmpb(ecx, static_cast<uint8_t>(SYMBOL_TYPE));
|
||||||
__ j(equal, ¬_identical);
|
__ j(equal, &runtime_call, Label::kFar);
|
||||||
|
if (strong()) {
|
||||||
|
// We have already tested for smis and heap numbers, so if both
|
||||||
|
// arguments are not strings we must proceed to the slow case.
|
||||||
|
__ test(ecx, Immediate(kIsNotStringMask));
|
||||||
|
__ j(not_zero, &runtime_call, Label::kFar);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
__ Move(eax, Immediate(Smi::FromInt(EQUAL)));
|
__ Move(eax, Immediate(Smi::FromInt(EQUAL)));
|
||||||
__ ret(0);
|
__ ret(0);
|
||||||
@ -1864,7 +1877,6 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
// Non-strict equality. Objects are unequal if
|
// Non-strict equality. Objects are unequal if
|
||||||
// they are both JSObjects and not undetectable,
|
// they are both JSObjects and not undetectable,
|
||||||
// and their pointers are different.
|
// and their pointers are different.
|
||||||
Label not_both_objects;
|
|
||||||
Label return_unequal;
|
Label return_unequal;
|
||||||
// At most one is a smi, so we can test for smi by adding the two.
|
// At most one is a smi, so we can test for smi by adding the two.
|
||||||
// A smi plus a heap object has the low bit set, a heap object plus
|
// A smi plus a heap object has the low bit set, a heap object plus
|
||||||
@ -1873,11 +1885,11 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
STATIC_ASSERT(kSmiTagMask == 1);
|
STATIC_ASSERT(kSmiTagMask == 1);
|
||||||
__ lea(ecx, Operand(eax, edx, times_1, 0));
|
__ lea(ecx, Operand(eax, edx, times_1, 0));
|
||||||
__ test(ecx, Immediate(kSmiTagMask));
|
__ test(ecx, Immediate(kSmiTagMask));
|
||||||
__ j(not_zero, ¬_both_objects, Label::kNear);
|
__ j(not_zero, &runtime_call, Label::kNear);
|
||||||
__ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
|
__ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
|
||||||
__ j(below, ¬_both_objects, Label::kNear);
|
__ j(below, &runtime_call, Label::kNear);
|
||||||
__ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ebx);
|
__ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ebx);
|
||||||
__ j(below, ¬_both_objects, Label::kNear);
|
__ j(below, &runtime_call, Label::kNear);
|
||||||
// We do not bail out after this point. Both are JSObjects, and
|
// We do not bail out after this point. Both are JSObjects, and
|
||||||
// they are equal if and only if both are undetectable.
|
// they are equal if and only if both are undetectable.
|
||||||
// The and of the undetectable flags is 1 if and only if they are equal.
|
// The and of the undetectable flags is 1 if and only if they are equal.
|
||||||
@ -1894,8 +1906,8 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
// Return non-equal by returning the non-zero object pointer in eax,
|
// Return non-equal by returning the non-zero object pointer in eax,
|
||||||
// or return equal if we fell through to here.
|
// or return equal if we fell through to here.
|
||||||
__ ret(0); // rax, rdx were pushed
|
__ ret(0); // rax, rdx were pushed
|
||||||
__ bind(¬_both_objects);
|
|
||||||
}
|
}
|
||||||
|
__ bind(&runtime_call);
|
||||||
|
|
||||||
// Push arguments below the return address.
|
// Push arguments below the return address.
|
||||||
__ pop(ecx);
|
__ pop(ecx);
|
||||||
@ -1907,7 +1919,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
if (cc == equal) {
|
if (cc == equal) {
|
||||||
builtin = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
|
builtin = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
|
||||||
} else {
|
} else {
|
||||||
builtin = Builtins::COMPARE;
|
builtin = strong() ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
|
||||||
__ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
|
__ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3638,7 +3650,7 @@ void CompareICStub::GenerateNumbers(MacroAssembler* masm) {
|
|||||||
|
|
||||||
__ bind(&unordered);
|
__ bind(&unordered);
|
||||||
__ bind(&generic_stub);
|
__ bind(&generic_stub);
|
||||||
CompareICStub stub(isolate(), op(), CompareICState::GENERIC,
|
CompareICStub stub(isolate(), op(), strong(), CompareICState::GENERIC,
|
||||||
CompareICState::GENERIC, CompareICState::GENERIC);
|
CompareICState::GENERIC, CompareICState::GENERIC);
|
||||||
__ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
|
__ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
|
||||||
|
|
||||||
|
@ -996,8 +996,8 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
|
|||||||
|
|
||||||
// Record position before stub call for type feedback.
|
// Record position before stub call for type feedback.
|
||||||
SetSourcePosition(clause->position());
|
SetSourcePosition(clause->position());
|
||||||
Handle<Code> ic =
|
Handle<Code> ic = CodeFactory::CompareIC(isolate(), Token::EQ_STRICT,
|
||||||
CodeFactory::CompareIC(isolate(), Token::EQ_STRICT).code();
|
language_mode()).code();
|
||||||
CallIC(ic, clause->CompareId());
|
CallIC(ic, clause->CompareId());
|
||||||
patch_site.EmitPatchInfo();
|
patch_site.EmitPatchInfo();
|
||||||
|
|
||||||
@ -5164,7 +5164,8 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
|
|||||||
|
|
||||||
// Record position and call the compare IC.
|
// Record position and call the compare IC.
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position());
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic =
|
||||||
|
CodeFactory::CompareIC(isolate(), op, language_mode()).code();
|
||||||
CallIC(ic, expr->CompareOperationFeedbackId());
|
CallIC(ic, expr->CompareOperationFeedbackId());
|
||||||
patch_site.EmitPatchInfo();
|
patch_site.EmitPatchInfo();
|
||||||
|
|
||||||
|
@ -2503,7 +2503,7 @@ static Condition ComputeCompareCondition(Token::Value op) {
|
|||||||
void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
|
void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
|
||||||
Token::Value op = instr->op();
|
Token::Value op = instr->op();
|
||||||
|
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op, SLOPPY).code();
|
||||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||||
|
|
||||||
Condition condition = ComputeCompareCondition(op);
|
Condition condition = ComputeCompareCondition(op);
|
||||||
@ -2774,7 +2774,8 @@ void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
|
|||||||
void LCodeGen::DoCmpT(LCmpT* instr) {
|
void LCodeGen::DoCmpT(LCmpT* instr) {
|
||||||
Token::Value op = instr->op();
|
Token::Value op = instr->op();
|
||||||
|
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic =
|
||||||
|
CodeFactory::CompareIC(isolate(), op, instr->language_mode()).code();
|
||||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||||
|
|
||||||
Condition condition = ComputeCompareCondition(op);
|
Condition condition = ComputeCompareCondition(op);
|
||||||
|
@ -1191,6 +1191,8 @@ class LCmpT final : public LTemplateInstruction<1, 3, 0> {
|
|||||||
DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
|
DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
|
||||||
DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
|
DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
|
||||||
|
|
||||||
|
LanguageMode language_mode() { return hydrogen()->language_mode(); }
|
||||||
|
|
||||||
LOperand* context() { return inputs_[0]; }
|
LOperand* context() { return inputs_[0]; }
|
||||||
Token::Value op() const { return hydrogen()->token(); }
|
Token::Value op() const { return hydrogen()->token(); }
|
||||||
};
|
};
|
||||||
|
16
src/ic/ic.cc
16
src/ic/ic.cc
@ -599,7 +599,8 @@ void CompareIC::Clear(Isolate* isolate, Address address, Code* target,
|
|||||||
CompareICStub stub(target->stub_key(), isolate);
|
CompareICStub stub(target->stub_key(), isolate);
|
||||||
// Only clear CompareICs that can retain objects.
|
// Only clear CompareICs that can retain objects.
|
||||||
if (stub.state() != CompareICState::KNOWN_OBJECT) return;
|
if (stub.state() != CompareICState::KNOWN_OBJECT) return;
|
||||||
SetTargetAtAddress(address, GetRawUninitialized(isolate, stub.op()),
|
SetTargetAtAddress(address,
|
||||||
|
GetRawUninitialized(isolate, stub.op(), stub.strong()),
|
||||||
constant_pool);
|
constant_pool);
|
||||||
PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK);
|
PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK);
|
||||||
}
|
}
|
||||||
@ -2678,8 +2679,9 @@ RUNTIME_FUNCTION(BinaryOpIC_MissWithAllocationSite) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) {
|
Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op,
|
||||||
CompareICStub stub(isolate, op, CompareICState::UNINITIALIZED,
|
bool strong) {
|
||||||
|
CompareICStub stub(isolate, op, strong, CompareICState::UNINITIALIZED,
|
||||||
CompareICState::UNINITIALIZED,
|
CompareICState::UNINITIALIZED,
|
||||||
CompareICState::UNINITIALIZED);
|
CompareICState::UNINITIALIZED);
|
||||||
Code* code = NULL;
|
Code* code = NULL;
|
||||||
@ -2688,8 +2690,9 @@ Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) {
|
Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op,
|
||||||
CompareICStub stub(isolate, op, CompareICState::UNINITIALIZED,
|
bool strong) {
|
||||||
|
CompareICStub stub(isolate, op, strong, CompareICState::UNINITIALIZED,
|
||||||
CompareICState::UNINITIALIZED,
|
CompareICState::UNINITIALIZED,
|
||||||
CompareICState::UNINITIALIZED);
|
CompareICState::UNINITIALIZED);
|
||||||
return stub.GetCode();
|
return stub.GetCode();
|
||||||
@ -2706,7 +2709,8 @@ Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
|
|||||||
CompareICState::State state = CompareICState::TargetState(
|
CompareICState::State state = CompareICState::TargetState(
|
||||||
old_stub.state(), old_stub.left(), old_stub.right(), op_,
|
old_stub.state(), old_stub.left(), old_stub.right(), op_,
|
||||||
HasInlinedSmiCode(address()), x, y);
|
HasInlinedSmiCode(address()), x, y);
|
||||||
CompareICStub stub(isolate(), op_, new_left, new_right, state);
|
CompareICStub stub(isolate(), op_, old_stub.strong(), new_left, new_right,
|
||||||
|
state);
|
||||||
if (state == CompareICState::KNOWN_OBJECT) {
|
if (state == CompareICState::KNOWN_OBJECT) {
|
||||||
stub.set_known_map(
|
stub.set_known_map(
|
||||||
Handle<Map>(Handle<JSObject>::cast(x)->map(), isolate()));
|
Handle<Map>(Handle<JSObject>::cast(x)->map(), isolate()));
|
||||||
|
@ -704,7 +704,8 @@ class CompareIC : public IC {
|
|||||||
static Condition ComputeCondition(Token::Value op);
|
static Condition ComputeCondition(Token::Value op);
|
||||||
|
|
||||||
// Factory method for getting an uninitialized compare stub.
|
// Factory method for getting an uninitialized compare stub.
|
||||||
static Handle<Code> GetUninitialized(Isolate* isolate, Token::Value op);
|
static Handle<Code> GetUninitialized(Isolate* isolate, Token::Value op,
|
||||||
|
bool strong);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool HasInlinedSmiCode(Address address);
|
static bool HasInlinedSmiCode(Address address);
|
||||||
@ -712,7 +713,8 @@ class CompareIC : public IC {
|
|||||||
bool strict() const { return op_ == Token::EQ_STRICT; }
|
bool strict() const { return op_ == Token::EQ_STRICT; }
|
||||||
Condition GetCondition() const { return ComputeCondition(op_); }
|
Condition GetCondition() const { return ComputeCondition(op_); }
|
||||||
|
|
||||||
static Code* GetRawUninitialized(Isolate* isolate, Token::Value op);
|
static Code* GetRawUninitialized(Isolate* isolate, Token::Value op,
|
||||||
|
bool strong);
|
||||||
|
|
||||||
static void Clear(Isolate* isolate, Address address, Code* target,
|
static void Clear(Isolate* isolate, Address address, Code* target,
|
||||||
ConstantPoolArray* constant_pool);
|
ConstantPoolArray* constant_pool);
|
||||||
|
@ -93,9 +93,8 @@ void InternalArrayNArgumentsConstructorStub::InitializeDescriptor(
|
|||||||
#define __ ACCESS_MASM(masm)
|
#define __ ACCESS_MASM(masm)
|
||||||
|
|
||||||
|
|
||||||
static void EmitIdenticalObjectComparison(MacroAssembler* masm,
|
static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow,
|
||||||
Label* slow,
|
Condition cc, bool strong);
|
||||||
Condition cc);
|
|
||||||
static void EmitSmiNonsmiComparison(MacroAssembler* masm,
|
static void EmitSmiNonsmiComparison(MacroAssembler* masm,
|
||||||
Register lhs,
|
Register lhs,
|
||||||
Register rhs,
|
Register rhs,
|
||||||
@ -276,9 +275,8 @@ void DoubleToIStub::Generate(MacroAssembler* masm) {
|
|||||||
// Handle the case where the lhs and rhs are the same object.
|
// Handle the case where the lhs and rhs are the same object.
|
||||||
// Equality is almost reflexive (everything but NaN), so this is a test
|
// Equality is almost reflexive (everything but NaN), so this is a test
|
||||||
// for "identity and not NaN".
|
// for "identity and not NaN".
|
||||||
static void EmitIdenticalObjectComparison(MacroAssembler* masm,
|
static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow,
|
||||||
Label* slow,
|
Condition cc, bool strong) {
|
||||||
Condition cc) {
|
|
||||||
Label not_identical;
|
Label not_identical;
|
||||||
Label heap_number, return_equal;
|
Label heap_number, return_equal;
|
||||||
Register exp_mask_reg = t5;
|
Register exp_mask_reg = t5;
|
||||||
@ -293,14 +291,31 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm,
|
|||||||
// Smis. If it's not a heap number, then return equal.
|
// Smis. If it's not a heap number, then return equal.
|
||||||
__ GetObjectType(a0, t4, t4);
|
__ GetObjectType(a0, t4, t4);
|
||||||
if (cc == less || cc == greater) {
|
if (cc == less || cc == greater) {
|
||||||
|
// Call runtime on identical JSObjects.
|
||||||
__ Branch(slow, greater, t4, Operand(FIRST_SPEC_OBJECT_TYPE));
|
__ Branch(slow, greater, t4, Operand(FIRST_SPEC_OBJECT_TYPE));
|
||||||
|
// Call runtime on identical symbols since we need to throw a TypeError.
|
||||||
__ Branch(slow, eq, t4, Operand(SYMBOL_TYPE));
|
__ Branch(slow, eq, t4, Operand(SYMBOL_TYPE));
|
||||||
|
if (strong) {
|
||||||
|
// Call the runtime on anything that is converted in the semantics, since
|
||||||
|
// we need to throw a TypeError. Smis have already been ruled out.
|
||||||
|
__ Branch(&return_equal, eq, t4, Operand(HEAP_NUMBER_TYPE));
|
||||||
|
__ And(t4, t4, Operand(kIsNotStringMask));
|
||||||
|
__ Branch(slow, ne, t4, Operand(zero_reg));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
__ Branch(&heap_number, eq, t4, Operand(HEAP_NUMBER_TYPE));
|
__ Branch(&heap_number, eq, t4, Operand(HEAP_NUMBER_TYPE));
|
||||||
// Comparing JS objects with <=, >= is complicated.
|
// Comparing JS objects with <=, >= is complicated.
|
||||||
if (cc != eq) {
|
if (cc != eq) {
|
||||||
__ Branch(slow, greater, t4, Operand(FIRST_SPEC_OBJECT_TYPE));
|
__ Branch(slow, greater, t4, Operand(FIRST_SPEC_OBJECT_TYPE));
|
||||||
|
// Call runtime on identical symbols since we need to throw a TypeError.
|
||||||
__ Branch(slow, eq, t4, Operand(SYMBOL_TYPE));
|
__ Branch(slow, eq, t4, Operand(SYMBOL_TYPE));
|
||||||
|
if (strong) {
|
||||||
|
// Call the runtime on anything that is converted in the semantics,
|
||||||
|
// since we need to throw a TypeError. Smis and heap numbers have
|
||||||
|
// already been ruled out.
|
||||||
|
__ And(t4, t4, Operand(kIsNotStringMask));
|
||||||
|
__ Branch(slow, ne, t4, Operand(zero_reg));
|
||||||
|
}
|
||||||
// Normally here we fall through to return_equal, but undefined is
|
// Normally here we fall through to return_equal, but undefined is
|
||||||
// special: (undefined == undefined) == true, but
|
// special: (undefined == undefined) == true, but
|
||||||
// (undefined <= undefined) == false! See ECMAScript 11.8.5.
|
// (undefined <= undefined) == false! See ECMAScript 11.8.5.
|
||||||
@ -585,7 +600,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
|
|
||||||
// Handle the case where the objects are identical. Either returns the answer
|
// Handle the case where the objects are identical. Either returns the answer
|
||||||
// or goes to slow. Only falls through if the objects were not identical.
|
// or goes to slow. Only falls through if the objects were not identical.
|
||||||
EmitIdenticalObjectComparison(masm, &slow, cc);
|
EmitIdenticalObjectComparison(masm, &slow, cc, strong());
|
||||||
|
|
||||||
// If either is a Smi (we know that not both are), then they can only
|
// If either is a Smi (we know that not both are), then they can only
|
||||||
// be strictly equal if the other is a HeapNumber.
|
// be strictly equal if the other is a HeapNumber.
|
||||||
@ -713,7 +728,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
if (cc == eq) {
|
if (cc == eq) {
|
||||||
native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
|
native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
|
||||||
} else {
|
} else {
|
||||||
native = Builtins::COMPARE;
|
native = strong() ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
|
||||||
int ncr; // NaN compare result.
|
int ncr; // NaN compare result.
|
||||||
if (cc == lt || cc == le) {
|
if (cc == lt || cc == le) {
|
||||||
ncr = GREATER;
|
ncr = GREATER;
|
||||||
@ -3743,7 +3758,7 @@ void CompareICStub::GenerateNumbers(MacroAssembler* masm) {
|
|||||||
|
|
||||||
__ bind(&unordered);
|
__ bind(&unordered);
|
||||||
__ bind(&generic_stub);
|
__ bind(&generic_stub);
|
||||||
CompareICStub stub(isolate(), op(), CompareICState::GENERIC,
|
CompareICStub stub(isolate(), op(), strong(), CompareICState::GENERIC,
|
||||||
CompareICState::GENERIC, CompareICState::GENERIC);
|
CompareICState::GENERIC, CompareICState::GENERIC);
|
||||||
__ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
|
__ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
|
||||||
|
|
||||||
|
@ -1053,8 +1053,8 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
|
|||||||
|
|
||||||
// Record position before stub call for type feedback.
|
// Record position before stub call for type feedback.
|
||||||
SetSourcePosition(clause->position());
|
SetSourcePosition(clause->position());
|
||||||
Handle<Code> ic =
|
Handle<Code> ic = CodeFactory::CompareIC(isolate(), Token::EQ_STRICT,
|
||||||
CodeFactory::CompareIC(isolate(), Token::EQ_STRICT).code();
|
language_mode()).code();
|
||||||
CallIC(ic, clause->CompareId());
|
CallIC(ic, clause->CompareId());
|
||||||
patch_site.EmitPatchInfo();
|
patch_site.EmitPatchInfo();
|
||||||
|
|
||||||
@ -5238,7 +5238,8 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
|
|||||||
}
|
}
|
||||||
// Record position and call the compare IC.
|
// Record position and call the compare IC.
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position());
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic =
|
||||||
|
CodeFactory::CompareIC(isolate(), op, language_mode()).code();
|
||||||
CallIC(ic, expr->CompareOperationFeedbackId());
|
CallIC(ic, expr->CompareOperationFeedbackId());
|
||||||
patch_site.EmitPatchInfo();
|
patch_site.EmitPatchInfo();
|
||||||
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
|
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
|
||||||
|
@ -2543,7 +2543,7 @@ void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
|
|||||||
DCHECK(ToRegister(instr->context()).is(cp));
|
DCHECK(ToRegister(instr->context()).is(cp));
|
||||||
Token::Value op = instr->op();
|
Token::Value op = instr->op();
|
||||||
|
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op, SLOPPY).code();
|
||||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||||
|
|
||||||
Condition condition = ComputeCompareCondition(op);
|
Condition condition = ComputeCompareCondition(op);
|
||||||
@ -2845,7 +2845,8 @@ void LCodeGen::DoCmpT(LCmpT* instr) {
|
|||||||
DCHECK(ToRegister(instr->context()).is(cp));
|
DCHECK(ToRegister(instr->context()).is(cp));
|
||||||
Token::Value op = instr->op();
|
Token::Value op = instr->op();
|
||||||
|
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic =
|
||||||
|
CodeFactory::CompareIC(isolate(), op, instr->language_mode()).code();
|
||||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||||
// On MIPS there is no need for a "no inlined smi code" marker (nop).
|
// On MIPS there is no need for a "no inlined smi code" marker (nop).
|
||||||
|
|
||||||
|
@ -1175,6 +1175,8 @@ class LCmpT final : public LTemplateInstruction<1, 3, 0> {
|
|||||||
DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
|
DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
|
||||||
DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
|
DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
|
||||||
|
|
||||||
|
LanguageMode language_mode() { return hydrogen()->language_mode(); }
|
||||||
|
|
||||||
Token::Value op() const { return hydrogen()->token(); }
|
Token::Value op() const { return hydrogen()->token(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -92,9 +92,8 @@ void InternalArrayNArgumentsConstructorStub::InitializeDescriptor(
|
|||||||
#define __ ACCESS_MASM(masm)
|
#define __ ACCESS_MASM(masm)
|
||||||
|
|
||||||
|
|
||||||
static void EmitIdenticalObjectComparison(MacroAssembler* masm,
|
static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow,
|
||||||
Label* slow,
|
Condition cc, bool strong);
|
||||||
Condition cc);
|
|
||||||
static void EmitSmiNonsmiComparison(MacroAssembler* masm,
|
static void EmitSmiNonsmiComparison(MacroAssembler* masm,
|
||||||
Register lhs,
|
Register lhs,
|
||||||
Register rhs,
|
Register rhs,
|
||||||
@ -272,9 +271,8 @@ void DoubleToIStub::Generate(MacroAssembler* masm) {
|
|||||||
// Handle the case where the lhs and rhs are the same object.
|
// Handle the case where the lhs and rhs are the same object.
|
||||||
// Equality is almost reflexive (everything but NaN), so this is a test
|
// Equality is almost reflexive (everything but NaN), so this is a test
|
||||||
// for "identity and not NaN".
|
// for "identity and not NaN".
|
||||||
static void EmitIdenticalObjectComparison(MacroAssembler* masm,
|
static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow,
|
||||||
Label* slow,
|
Condition cc, bool strong) {
|
||||||
Condition cc) {
|
|
||||||
Label not_identical;
|
Label not_identical;
|
||||||
Label heap_number, return_equal;
|
Label heap_number, return_equal;
|
||||||
Register exp_mask_reg = t1;
|
Register exp_mask_reg = t1;
|
||||||
@ -289,14 +287,31 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm,
|
|||||||
// Smis. If it's not a heap number, then return equal.
|
// Smis. If it's not a heap number, then return equal.
|
||||||
__ GetObjectType(a0, t0, t0);
|
__ GetObjectType(a0, t0, t0);
|
||||||
if (cc == less || cc == greater) {
|
if (cc == less || cc == greater) {
|
||||||
|
// Call runtime on identical JSObjects.
|
||||||
__ Branch(slow, greater, t0, Operand(FIRST_SPEC_OBJECT_TYPE));
|
__ Branch(slow, greater, t0, Operand(FIRST_SPEC_OBJECT_TYPE));
|
||||||
|
// Call runtime on identical symbols since we need to throw a TypeError.
|
||||||
__ Branch(slow, eq, t0, Operand(SYMBOL_TYPE));
|
__ Branch(slow, eq, t0, Operand(SYMBOL_TYPE));
|
||||||
|
if (strong) {
|
||||||
|
// Call the runtime on anything that is converted in the semantics, since
|
||||||
|
// we need to throw a TypeError. Smis have already been ruled out.
|
||||||
|
__ Branch(&return_equal, eq, t0, Operand(HEAP_NUMBER_TYPE));
|
||||||
|
__ And(t0, t0, Operand(kIsNotStringMask));
|
||||||
|
__ Branch(slow, ne, t0, Operand(zero_reg));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
__ Branch(&heap_number, eq, t0, Operand(HEAP_NUMBER_TYPE));
|
__ Branch(&heap_number, eq, t0, Operand(HEAP_NUMBER_TYPE));
|
||||||
// Comparing JS objects with <=, >= is complicated.
|
// Comparing JS objects with <=, >= is complicated.
|
||||||
if (cc != eq) {
|
if (cc != eq) {
|
||||||
__ Branch(slow, greater, t0, Operand(FIRST_SPEC_OBJECT_TYPE));
|
__ Branch(slow, greater, t0, Operand(FIRST_SPEC_OBJECT_TYPE));
|
||||||
|
// Call runtime on identical symbols since we need to throw a TypeError.
|
||||||
__ Branch(slow, eq, t0, Operand(SYMBOL_TYPE));
|
__ Branch(slow, eq, t0, Operand(SYMBOL_TYPE));
|
||||||
|
if (strong) {
|
||||||
|
// Call the runtime on anything that is converted in the semantics,
|
||||||
|
// since we need to throw a TypeError. Smis and heap numbers have
|
||||||
|
// already been ruled out.
|
||||||
|
__ And(t0, t0, Operand(kIsNotStringMask));
|
||||||
|
__ Branch(slow, ne, t0, Operand(zero_reg));
|
||||||
|
}
|
||||||
// Normally here we fall through to return_equal, but undefined is
|
// Normally here we fall through to return_equal, but undefined is
|
||||||
// special: (undefined == undefined) == true, but
|
// special: (undefined == undefined) == true, but
|
||||||
// (undefined <= undefined) == false! See ECMAScript 11.8.5.
|
// (undefined <= undefined) == false! See ECMAScript 11.8.5.
|
||||||
@ -580,7 +595,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
|
|
||||||
// Handle the case where the objects are identical. Either returns the answer
|
// Handle the case where the objects are identical. Either returns the answer
|
||||||
// or goes to slow. Only falls through if the objects were not identical.
|
// or goes to slow. Only falls through if the objects were not identical.
|
||||||
EmitIdenticalObjectComparison(masm, &slow, cc);
|
EmitIdenticalObjectComparison(masm, &slow, cc, strong());
|
||||||
|
|
||||||
// If either is a Smi (we know that not both are), then they can only
|
// If either is a Smi (we know that not both are), then they can only
|
||||||
// be strictly equal if the other is a HeapNumber.
|
// be strictly equal if the other is a HeapNumber.
|
||||||
@ -708,7 +723,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
if (cc == eq) {
|
if (cc == eq) {
|
||||||
native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
|
native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
|
||||||
} else {
|
} else {
|
||||||
native = Builtins::COMPARE;
|
native = strong() ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
|
||||||
int ncr; // NaN compare result.
|
int ncr; // NaN compare result.
|
||||||
if (cc == lt || cc == le) {
|
if (cc == lt || cc == le) {
|
||||||
ncr = GREATER;
|
ncr = GREATER;
|
||||||
@ -3786,7 +3801,7 @@ void CompareICStub::GenerateNumbers(MacroAssembler* masm) {
|
|||||||
|
|
||||||
__ bind(&unordered);
|
__ bind(&unordered);
|
||||||
__ bind(&generic_stub);
|
__ bind(&generic_stub);
|
||||||
CompareICStub stub(isolate(), op(), CompareICState::GENERIC,
|
CompareICStub stub(isolate(), op(), strong(), CompareICState::GENERIC,
|
||||||
CompareICState::GENERIC, CompareICState::GENERIC);
|
CompareICState::GENERIC, CompareICState::GENERIC);
|
||||||
__ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
|
__ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
|
||||||
|
|
||||||
|
@ -1050,8 +1050,8 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
|
|||||||
|
|
||||||
// Record position before stub call for type feedback.
|
// Record position before stub call for type feedback.
|
||||||
SetSourcePosition(clause->position());
|
SetSourcePosition(clause->position());
|
||||||
Handle<Code> ic =
|
Handle<Code> ic = CodeFactory::CompareIC(isolate(), Token::EQ_STRICT,
|
||||||
CodeFactory::CompareIC(isolate(), Token::EQ_STRICT).code();
|
language_mode()).code();
|
||||||
CallIC(ic, clause->CompareId());
|
CallIC(ic, clause->CompareId());
|
||||||
patch_site.EmitPatchInfo();
|
patch_site.EmitPatchInfo();
|
||||||
|
|
||||||
@ -5241,7 +5241,8 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
|
|||||||
}
|
}
|
||||||
// Record position and call the compare IC.
|
// Record position and call the compare IC.
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position());
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic =
|
||||||
|
CodeFactory::CompareIC(isolate(), op, language_mode()).code();
|
||||||
CallIC(ic, expr->CompareOperationFeedbackId());
|
CallIC(ic, expr->CompareOperationFeedbackId());
|
||||||
patch_site.EmitPatchInfo();
|
patch_site.EmitPatchInfo();
|
||||||
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
|
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
|
||||||
|
@ -2542,7 +2542,7 @@ void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
|
|||||||
DCHECK(ToRegister(instr->context()).is(cp));
|
DCHECK(ToRegister(instr->context()).is(cp));
|
||||||
Token::Value op = instr->op();
|
Token::Value op = instr->op();
|
||||||
|
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op, SLOPPY).code();
|
||||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||||
|
|
||||||
Condition condition = ComputeCompareCondition(op);
|
Condition condition = ComputeCompareCondition(op);
|
||||||
@ -2844,7 +2844,8 @@ void LCodeGen::DoCmpT(LCmpT* instr) {
|
|||||||
DCHECK(ToRegister(instr->context()).is(cp));
|
DCHECK(ToRegister(instr->context()).is(cp));
|
||||||
Token::Value op = instr->op();
|
Token::Value op = instr->op();
|
||||||
|
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic =
|
||||||
|
CodeFactory::CompareIC(isolate(), op, instr->language_mode()).code();
|
||||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||||
// On MIPS there is no need for a "no inlined smi code" marker (nop).
|
// On MIPS there is no need for a "no inlined smi code" marker (nop).
|
||||||
|
|
||||||
|
@ -1174,6 +1174,8 @@ class LCmpT final : public LTemplateInstruction<1, 3, 0> {
|
|||||||
DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
|
DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
|
||||||
DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
|
DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
|
||||||
|
|
||||||
|
LanguageMode language_mode() { return hydrogen()->language_mode(); }
|
||||||
|
|
||||||
Token::Value op() const { return hydrogen()->token(); }
|
Token::Value op() const { return hydrogen()->token(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ void InternalArrayNArgumentsConstructorStub::InitializeDescriptor(
|
|||||||
|
|
||||||
|
|
||||||
static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow,
|
static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow,
|
||||||
Condition cond);
|
Condition cond, bool strong);
|
||||||
static void EmitSmiNonsmiComparison(MacroAssembler* masm, Register lhs,
|
static void EmitSmiNonsmiComparison(MacroAssembler* masm, Register lhs,
|
||||||
Register rhs, Label* lhs_not_nan,
|
Register rhs, Label* lhs_not_nan,
|
||||||
Label* slow, bool strict);
|
Label* slow, bool strict);
|
||||||
@ -249,7 +249,7 @@ void DoubleToIStub::Generate(MacroAssembler* masm) {
|
|||||||
// Equality is almost reflexive (everything but NaN), so this is a test
|
// Equality is almost reflexive (everything but NaN), so this is a test
|
||||||
// for "identity and not NaN".
|
// for "identity and not NaN".
|
||||||
static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow,
|
static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow,
|
||||||
Condition cond) {
|
Condition cond, bool strong) {
|
||||||
Label not_identical;
|
Label not_identical;
|
||||||
Label heap_number, return_equal;
|
Label heap_number, return_equal;
|
||||||
__ cmp(r3, r4);
|
__ cmp(r3, r4);
|
||||||
@ -260,10 +260,20 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow,
|
|||||||
// They are both equal and they are not both Smis so both of them are not
|
// They are both equal and they are not both Smis so both of them are not
|
||||||
// Smis. If it's not a heap number, then return equal.
|
// Smis. If it's not a heap number, then return equal.
|
||||||
if (cond == lt || cond == gt) {
|
if (cond == lt || cond == gt) {
|
||||||
|
// Call runtime on identical JSObjects.
|
||||||
__ CompareObjectType(r3, r7, r7, FIRST_SPEC_OBJECT_TYPE);
|
__ CompareObjectType(r3, r7, r7, FIRST_SPEC_OBJECT_TYPE);
|
||||||
__ bge(slow);
|
__ bge(slow);
|
||||||
|
// Call runtime on identical symbols since we need to throw a TypeError.
|
||||||
__ cmpi(r7, Operand(SYMBOL_TYPE));
|
__ cmpi(r7, Operand(SYMBOL_TYPE));
|
||||||
__ beq(slow);
|
__ beq(slow);
|
||||||
|
if (strong) {
|
||||||
|
// Call the runtime on anything that is converted in the semantics, since
|
||||||
|
// we need to throw a TypeError. Smis have already been ruled out.
|
||||||
|
__ cmpi(r7, Operand(HEAP_NUMBER_TYPE));
|
||||||
|
__ beq(&return_equal);
|
||||||
|
__ andi(r7, r7, Operand(kIsNotStringMask));
|
||||||
|
__ bne(slow, cr0);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
__ CompareObjectType(r3, r7, r7, HEAP_NUMBER_TYPE);
|
__ CompareObjectType(r3, r7, r7, HEAP_NUMBER_TYPE);
|
||||||
__ beq(&heap_number);
|
__ beq(&heap_number);
|
||||||
@ -271,8 +281,16 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow,
|
|||||||
if (cond != eq) {
|
if (cond != eq) {
|
||||||
__ cmpi(r7, Operand(FIRST_SPEC_OBJECT_TYPE));
|
__ cmpi(r7, Operand(FIRST_SPEC_OBJECT_TYPE));
|
||||||
__ bge(slow);
|
__ bge(slow);
|
||||||
|
// Call runtime on identical symbols since we need to throw a TypeError.
|
||||||
__ cmpi(r7, Operand(SYMBOL_TYPE));
|
__ cmpi(r7, Operand(SYMBOL_TYPE));
|
||||||
__ beq(slow);
|
__ beq(slow);
|
||||||
|
if (strong) {
|
||||||
|
// Call the runtime on anything that is converted in the semantics,
|
||||||
|
// since we need to throw a TypeError. Smis and heap numbers have
|
||||||
|
// already been ruled out.
|
||||||
|
__ andi(r7, r7, Operand(kIsNotStringMask));
|
||||||
|
__ bne(slow, cr0);
|
||||||
|
}
|
||||||
// Normally here we fall through to return_equal, but undefined is
|
// Normally here we fall through to return_equal, but undefined is
|
||||||
// special: (undefined == undefined) == true, but
|
// special: (undefined == undefined) == true, but
|
||||||
// (undefined <= undefined) == false! See ECMAScript 11.8.5.
|
// (undefined <= undefined) == false! See ECMAScript 11.8.5.
|
||||||
@ -687,7 +705,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
if (cc == eq) {
|
if (cc == eq) {
|
||||||
native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
|
native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
|
||||||
} else {
|
} else {
|
||||||
native = Builtins::COMPARE;
|
native = strong() ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
|
||||||
int ncr; // NaN compare result
|
int ncr; // NaN compare result
|
||||||
if (cc == lt || cc == le) {
|
if (cc == lt || cc == le) {
|
||||||
ncr = GREATER;
|
ncr = GREATER;
|
||||||
@ -3780,7 +3798,7 @@ void CompareICStub::GenerateNumbers(MacroAssembler* masm) {
|
|||||||
|
|
||||||
__ bind(&unordered);
|
__ bind(&unordered);
|
||||||
__ bind(&generic_stub);
|
__ bind(&generic_stub);
|
||||||
CompareICStub stub(isolate(), op(), CompareICState::GENERIC,
|
CompareICStub stub(isolate(), op(), strong(), CompareICState::GENERIC,
|
||||||
CompareICState::GENERIC, CompareICState::GENERIC);
|
CompareICState::GENERIC, CompareICState::GENERIC);
|
||||||
__ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
|
__ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
|
||||||
|
|
||||||
|
@ -1017,8 +1017,8 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
|
|||||||
|
|
||||||
// Record position before stub call for type feedback.
|
// Record position before stub call for type feedback.
|
||||||
SetSourcePosition(clause->position());
|
SetSourcePosition(clause->position());
|
||||||
Handle<Code> ic =
|
Handle<Code> ic = CodeFactory::CompareIC(isolate(), Token::EQ_STRICT,
|
||||||
CodeFactory::CompareIC(isolate(), Token::EQ_STRICT).code();
|
language_mode()).code();
|
||||||
CallIC(ic, clause->CompareId());
|
CallIC(ic, clause->CompareId());
|
||||||
patch_site.EmitPatchInfo();
|
patch_site.EmitPatchInfo();
|
||||||
|
|
||||||
@ -5251,7 +5251,8 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
|
|||||||
|
|
||||||
// Record position and call the compare IC.
|
// Record position and call the compare IC.
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position());
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic =
|
||||||
|
CodeFactory::CompareIC(isolate(), op, language_mode()).code();
|
||||||
CallIC(ic, expr->CompareOperationFeedbackId());
|
CallIC(ic, expr->CompareOperationFeedbackId());
|
||||||
patch_site.EmitPatchInfo();
|
patch_site.EmitPatchInfo();
|
||||||
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
|
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
|
||||||
|
@ -2671,7 +2671,7 @@ void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
|
|||||||
DCHECK(ToRegister(instr->context()).is(cp));
|
DCHECK(ToRegister(instr->context()).is(cp));
|
||||||
Token::Value op = instr->op();
|
Token::Value op = instr->op();
|
||||||
|
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op, SLOPPY).code();
|
||||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||||
// This instruction also signals no smi code inlined
|
// This instruction also signals no smi code inlined
|
||||||
__ cmpi(r3, Operand::Zero());
|
__ cmpi(r3, Operand::Zero());
|
||||||
@ -2978,7 +2978,8 @@ void LCodeGen::DoCmpT(LCmpT* instr) {
|
|||||||
DCHECK(ToRegister(instr->context()).is(cp));
|
DCHECK(ToRegister(instr->context()).is(cp));
|
||||||
Token::Value op = instr->op();
|
Token::Value op = instr->op();
|
||||||
|
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic =
|
||||||
|
CodeFactory::CompareIC(isolate(), op, instr->language_mode()).code();
|
||||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||||
// This instruction also signals no smi code inlined
|
// This instruction also signals no smi code inlined
|
||||||
__ cmpi(r3, Operand::Zero());
|
__ cmpi(r3, Operand::Zero());
|
||||||
|
@ -1151,6 +1151,8 @@ class LCmpT final : public LTemplateInstruction<1, 3, 0> {
|
|||||||
DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
|
DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
|
||||||
DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
|
DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
|
||||||
|
|
||||||
|
LanguageMode language_mode() { return hydrogen()->language_mode(); }
|
||||||
|
|
||||||
Token::Value op() const { return hydrogen()->token(); }
|
Token::Value op() const { return hydrogen()->token(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
var EQUALS;
|
var EQUALS;
|
||||||
var STRICT_EQUALS;
|
var STRICT_EQUALS;
|
||||||
var COMPARE;
|
var COMPARE;
|
||||||
|
var COMPARE_STRONG;
|
||||||
var ADD;
|
var ADD;
|
||||||
var ADD_STRONG;
|
var ADD_STRONG;
|
||||||
var STRING_ADD_LEFT;
|
var STRING_ADD_LEFT;
|
||||||
@ -204,6 +205,14 @@ COMPARE = function COMPARE(x, ncr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Strong mode COMPARE throws if an implicit conversion would be performed
|
||||||
|
COMPARE_STRONG = function COMPARE_STRONG(x, ncr) {
|
||||||
|
if (IS_STRING(this) && IS_STRING(x)) return %_StringCompare(this, x);
|
||||||
|
if (IS_NUMBER(this) && IS_NUMBER(x)) return %NumberCompare(this, x, ncr);
|
||||||
|
|
||||||
|
throw %MakeTypeError('strong_implicit_cast');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* -----------------------------------
|
/* -----------------------------------
|
||||||
|
@ -1533,7 +1533,7 @@ static void BranchIfNotInternalizedString(MacroAssembler* masm,
|
|||||||
|
|
||||||
|
|
||||||
void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
||||||
Label check_unequal_objects, done;
|
Label runtime_call, check_unequal_objects, done;
|
||||||
Condition cc = GetCondition();
|
Condition cc = GetCondition();
|
||||||
Factory* factory = isolate()->factory();
|
Factory* factory = isolate()->factory();
|
||||||
|
|
||||||
@ -1566,13 +1566,18 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
if (cc != equal) {
|
if (cc != equal) {
|
||||||
// Check for undefined. undefined OP undefined is false even though
|
// Check for undefined. undefined OP undefined is false even though
|
||||||
// undefined == undefined.
|
// undefined == undefined.
|
||||||
Label check_for_nan;
|
|
||||||
__ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
|
__ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
|
||||||
|
if (strong()) {
|
||||||
|
// In strong mode, this comparison must throw, so call the runtime.
|
||||||
|
__ j(equal, &runtime_call, Label::kFar);
|
||||||
|
} else {
|
||||||
|
Label check_for_nan;
|
||||||
__ j(not_equal, &check_for_nan, Label::kNear);
|
__ j(not_equal, &check_for_nan, Label::kNear);
|
||||||
__ Set(rax, NegativeComparisonResult(cc));
|
__ Set(rax, NegativeComparisonResult(cc));
|
||||||
__ ret(0);
|
__ ret(0);
|
||||||
__ bind(&check_for_nan);
|
__ bind(&check_for_nan);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Test for NaN. Sadly, we can't just compare to Factory::nan_value(),
|
// Test for NaN. Sadly, we can't just compare to Factory::nan_value(),
|
||||||
// so we do the second best thing - test it ourselves.
|
// so we do the second best thing - test it ourselves.
|
||||||
@ -1582,12 +1587,20 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
factory->heap_number_map());
|
factory->heap_number_map());
|
||||||
__ j(equal, &heap_number, Label::kNear);
|
__ j(equal, &heap_number, Label::kNear);
|
||||||
if (cc != equal) {
|
if (cc != equal) {
|
||||||
|
__ movp(rcx, FieldOperand(rax, HeapObject::kMapOffset));
|
||||||
|
__ movzxbl(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset));
|
||||||
// Call runtime on identical objects. Otherwise return equal.
|
// Call runtime on identical objects. Otherwise return equal.
|
||||||
__ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx);
|
__ cmpb(rcx, Immediate(static_cast<uint8_t>(FIRST_SPEC_OBJECT_TYPE)));
|
||||||
__ j(above_equal, ¬_identical, Label::kNear);
|
__ j(above_equal, &runtime_call, Label::kFar);
|
||||||
// Call runtime on identical symbols since we need to throw a TypeError.
|
// Call runtime on identical symbols since we need to throw a TypeError.
|
||||||
__ CmpObjectType(rax, SYMBOL_TYPE, rcx);
|
__ cmpb(rcx, Immediate(static_cast<uint8_t>(SYMBOL_TYPE)));
|
||||||
__ j(equal, ¬_identical, Label::kNear);
|
__ j(equal, &runtime_call, Label::kFar);
|
||||||
|
if (strong()) {
|
||||||
|
// We have already tested for smis and heap numbers, so if both
|
||||||
|
// arguments are not strings we must proceed to the slow case.
|
||||||
|
__ testb(rcx, Immediate(kIsNotStringMask));
|
||||||
|
__ j(not_zero, &runtime_call, Label::kFar);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
__ Set(rax, EQUAL);
|
__ Set(rax, EQUAL);
|
||||||
__ ret(0);
|
__ ret(0);
|
||||||
@ -1734,7 +1747,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
// Not strict equality. Objects are unequal if
|
// Not strict equality. Objects are unequal if
|
||||||
// they are both JSObjects and not undetectable,
|
// they are both JSObjects and not undetectable,
|
||||||
// and their pointers are different.
|
// and their pointers are different.
|
||||||
Label not_both_objects, return_unequal;
|
Label return_unequal;
|
||||||
// At most one is a smi, so we can test for smi by adding the two.
|
// At most one is a smi, so we can test for smi by adding the two.
|
||||||
// A smi plus a heap object has the low bit set, a heap object plus
|
// A smi plus a heap object has the low bit set, a heap object plus
|
||||||
// a heap object has the low bit clear.
|
// a heap object has the low bit clear.
|
||||||
@ -1742,11 +1755,11 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
STATIC_ASSERT(kSmiTagMask == 1);
|
STATIC_ASSERT(kSmiTagMask == 1);
|
||||||
__ leap(rcx, Operand(rax, rdx, times_1, 0));
|
__ leap(rcx, Operand(rax, rdx, times_1, 0));
|
||||||
__ testb(rcx, Immediate(kSmiTagMask));
|
__ testb(rcx, Immediate(kSmiTagMask));
|
||||||
__ j(not_zero, ¬_both_objects, Label::kNear);
|
__ j(not_zero, &runtime_call, Label::kNear);
|
||||||
__ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rbx);
|
__ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rbx);
|
||||||
__ j(below, ¬_both_objects, Label::kNear);
|
__ j(below, &runtime_call, Label::kNear);
|
||||||
__ CmpObjectType(rdx, FIRST_SPEC_OBJECT_TYPE, rcx);
|
__ CmpObjectType(rdx, FIRST_SPEC_OBJECT_TYPE, rcx);
|
||||||
__ j(below, ¬_both_objects, Label::kNear);
|
__ j(below, &runtime_call, Label::kNear);
|
||||||
__ testb(FieldOperand(rbx, Map::kBitFieldOffset),
|
__ testb(FieldOperand(rbx, Map::kBitFieldOffset),
|
||||||
Immediate(1 << Map::kIsUndetectable));
|
Immediate(1 << Map::kIsUndetectable));
|
||||||
__ j(zero, &return_unequal, Label::kNear);
|
__ j(zero, &return_unequal, Label::kNear);
|
||||||
@ -1760,8 +1773,8 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
// Return non-equal by returning the non-zero object pointer in rax,
|
// Return non-equal by returning the non-zero object pointer in rax,
|
||||||
// or return equal if we fell through to here.
|
// or return equal if we fell through to here.
|
||||||
__ ret(0);
|
__ ret(0);
|
||||||
__ bind(¬_both_objects);
|
|
||||||
}
|
}
|
||||||
|
__ bind(&runtime_call);
|
||||||
|
|
||||||
// Push arguments below the return address to prepare jump to builtin.
|
// Push arguments below the return address to prepare jump to builtin.
|
||||||
__ PopReturnAddressTo(rcx);
|
__ PopReturnAddressTo(rcx);
|
||||||
@ -1773,7 +1786,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
if (cc == equal) {
|
if (cc == equal) {
|
||||||
builtin = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
|
builtin = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
|
||||||
} else {
|
} else {
|
||||||
builtin = Builtins::COMPARE;
|
builtin = strong() ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
|
||||||
__ Push(Smi::FromInt(NegativeComparisonResult(cc)));
|
__ Push(Smi::FromInt(NegativeComparisonResult(cc)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3598,7 +3611,7 @@ void CompareICStub::GenerateNumbers(MacroAssembler* masm) {
|
|||||||
|
|
||||||
__ bind(&unordered);
|
__ bind(&unordered);
|
||||||
__ bind(&generic_stub);
|
__ bind(&generic_stub);
|
||||||
CompareICStub stub(isolate(), op(), CompareICState::GENERIC,
|
CompareICStub stub(isolate(), op(), strong(), CompareICState::GENERIC,
|
||||||
CompareICState::GENERIC, CompareICState::GENERIC);
|
CompareICState::GENERIC, CompareICState::GENERIC);
|
||||||
__ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
|
__ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
|
||||||
|
|
||||||
|
@ -1019,8 +1019,8 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
|
|||||||
|
|
||||||
// Record position before stub call for type feedback.
|
// Record position before stub call for type feedback.
|
||||||
SetSourcePosition(clause->position());
|
SetSourcePosition(clause->position());
|
||||||
Handle<Code> ic =
|
Handle<Code> ic = CodeFactory::CompareIC(isolate(), Token::EQ_STRICT,
|
||||||
CodeFactory::CompareIC(isolate(), Token::EQ_STRICT).code();
|
language_mode()).code();
|
||||||
CallIC(ic, clause->CompareId());
|
CallIC(ic, clause->CompareId());
|
||||||
patch_site.EmitPatchInfo();
|
patch_site.EmitPatchInfo();
|
||||||
|
|
||||||
@ -5181,7 +5181,8 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
|
|||||||
|
|
||||||
// Record position and call the compare IC.
|
// Record position and call the compare IC.
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position());
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic =
|
||||||
|
CodeFactory::CompareIC(isolate(), op, language_mode()).code();
|
||||||
CallIC(ic, expr->CompareOperationFeedbackId());
|
CallIC(ic, expr->CompareOperationFeedbackId());
|
||||||
patch_site.EmitPatchInfo();
|
patch_site.EmitPatchInfo();
|
||||||
|
|
||||||
|
@ -2549,7 +2549,7 @@ void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
|
|||||||
DCHECK(ToRegister(instr->context()).is(rsi));
|
DCHECK(ToRegister(instr->context()).is(rsi));
|
||||||
Token::Value op = instr->op();
|
Token::Value op = instr->op();
|
||||||
|
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op, SLOPPY).code();
|
||||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||||
|
|
||||||
Condition condition = TokenToCondition(op, false);
|
Condition condition = TokenToCondition(op, false);
|
||||||
@ -2833,7 +2833,8 @@ void LCodeGen::DoCmpT(LCmpT* instr) {
|
|||||||
DCHECK(ToRegister(instr->context()).is(rsi));
|
DCHECK(ToRegister(instr->context()).is(rsi));
|
||||||
Token::Value op = instr->op();
|
Token::Value op = instr->op();
|
||||||
|
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic =
|
||||||
|
CodeFactory::CompareIC(isolate(), op, instr->language_mode()).code();
|
||||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||||
|
|
||||||
Condition condition = TokenToCondition(op, false);
|
Condition condition = TokenToCondition(op, false);
|
||||||
|
@ -1174,6 +1174,8 @@ class LCmpT final : public LTemplateInstruction<1, 3, 0> {
|
|||||||
DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
|
DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
|
||||||
DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
|
DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
|
||||||
|
|
||||||
|
LanguageMode language_mode() { return hydrogen()->language_mode(); }
|
||||||
|
|
||||||
Token::Value op() const { return hydrogen()->token(); }
|
Token::Value op() const { return hydrogen()->token(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1341,7 +1341,7 @@ static void BranchIfNotInternalizedString(MacroAssembler* masm,
|
|||||||
|
|
||||||
|
|
||||||
void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
||||||
Label check_unequal_objects;
|
Label runtime_call, check_unequal_objects;
|
||||||
Condition cc = GetCondition();
|
Condition cc = GetCondition();
|
||||||
|
|
||||||
Label miss;
|
Label miss;
|
||||||
@ -1375,26 +1375,39 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
if (cc != equal) {
|
if (cc != equal) {
|
||||||
// Check for undefined. undefined OP undefined is false even though
|
// Check for undefined. undefined OP undefined is false even though
|
||||||
// undefined == undefined.
|
// undefined == undefined.
|
||||||
Label check_for_nan;
|
|
||||||
__ cmp(edx, isolate()->factory()->undefined_value());
|
__ cmp(edx, isolate()->factory()->undefined_value());
|
||||||
|
if (strong()) {
|
||||||
|
// In strong mode, this comparison must throw, so call the runtime.
|
||||||
|
__ j(equal, &runtime_call, Label::kFar);
|
||||||
|
} else {
|
||||||
|
Label check_for_nan;
|
||||||
__ j(not_equal, &check_for_nan, Label::kNear);
|
__ j(not_equal, &check_for_nan, Label::kNear);
|
||||||
__ Move(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
|
__ Move(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
|
||||||
__ ret(0);
|
__ ret(0);
|
||||||
__ bind(&check_for_nan);
|
__ bind(&check_for_nan);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Test for NaN. Compare heap numbers in a general way,
|
// Test for NaN. Compare heap numbers in a general way,
|
||||||
// to hanlde NaNs correctly.
|
// to handle NaNs correctly.
|
||||||
__ cmp(FieldOperand(edx, HeapObject::kMapOffset),
|
__ cmp(FieldOperand(edx, HeapObject::kMapOffset),
|
||||||
Immediate(isolate()->factory()->heap_number_map()));
|
Immediate(isolate()->factory()->heap_number_map()));
|
||||||
__ j(equal, &generic_heap_number_comparison, Label::kNear);
|
__ j(equal, &generic_heap_number_comparison, Label::kNear);
|
||||||
if (cc != equal) {
|
if (cc != equal) {
|
||||||
|
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
|
||||||
|
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
|
||||||
// Call runtime on identical JSObjects. Otherwise return equal.
|
// Call runtime on identical JSObjects. Otherwise return equal.
|
||||||
__ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
|
__ cmpb(ecx, static_cast<uint8_t>(FIRST_SPEC_OBJECT_TYPE));
|
||||||
__ j(above_equal, ¬_identical);
|
__ j(above_equal, &runtime_call, Label::kFar);
|
||||||
// Call runtime on identical symbols since we need to throw a TypeError.
|
// Call runtime on identical symbols since we need to throw a TypeError.
|
||||||
__ CmpObjectType(eax, SYMBOL_TYPE, ecx);
|
__ cmpb(ecx, static_cast<uint8_t>(SYMBOL_TYPE));
|
||||||
__ j(equal, ¬_identical);
|
__ j(equal, &runtime_call, Label::kFar);
|
||||||
|
if (strong()) {
|
||||||
|
// We have already tested for smis and heap numbers, so if both
|
||||||
|
// arguments are not strings we must proceed to the slow case.
|
||||||
|
__ test(ecx, Immediate(kIsNotStringMask));
|
||||||
|
__ j(not_zero, &runtime_call, Label::kFar);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
__ Move(eax, Immediate(Smi::FromInt(EQUAL)));
|
__ Move(eax, Immediate(Smi::FromInt(EQUAL)));
|
||||||
__ ret(0);
|
__ ret(0);
|
||||||
@ -1551,7 +1564,6 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
// Non-strict equality. Objects are unequal if
|
// Non-strict equality. Objects are unequal if
|
||||||
// they are both JSObjects and not undetectable,
|
// they are both JSObjects and not undetectable,
|
||||||
// and their pointers are different.
|
// and their pointers are different.
|
||||||
Label not_both_objects;
|
|
||||||
Label return_unequal;
|
Label return_unequal;
|
||||||
// At most one is a smi, so we can test for smi by adding the two.
|
// At most one is a smi, so we can test for smi by adding the two.
|
||||||
// A smi plus a heap object has the low bit set, a heap object plus
|
// A smi plus a heap object has the low bit set, a heap object plus
|
||||||
@ -1560,11 +1572,11 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
STATIC_ASSERT(kSmiTagMask == 1);
|
STATIC_ASSERT(kSmiTagMask == 1);
|
||||||
__ lea(ecx, Operand(eax, edx, times_1, 0));
|
__ lea(ecx, Operand(eax, edx, times_1, 0));
|
||||||
__ test(ecx, Immediate(kSmiTagMask));
|
__ test(ecx, Immediate(kSmiTagMask));
|
||||||
__ j(not_zero, ¬_both_objects, Label::kNear);
|
__ j(not_zero, &runtime_call, Label::kNear);
|
||||||
__ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
|
__ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
|
||||||
__ j(below, ¬_both_objects, Label::kNear);
|
__ j(below, &runtime_call, Label::kNear);
|
||||||
__ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ebx);
|
__ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ebx);
|
||||||
__ j(below, ¬_both_objects, Label::kNear);
|
__ j(below, &runtime_call, Label::kNear);
|
||||||
// We do not bail out after this point. Both are JSObjects, and
|
// We do not bail out after this point. Both are JSObjects, and
|
||||||
// they are equal if and only if both are undetectable.
|
// they are equal if and only if both are undetectable.
|
||||||
// The and of the undetectable flags is 1 if and only if they are equal.
|
// The and of the undetectable flags is 1 if and only if they are equal.
|
||||||
@ -1581,8 +1593,8 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
// Return non-equal by returning the non-zero object pointer in eax,
|
// Return non-equal by returning the non-zero object pointer in eax,
|
||||||
// or return equal if we fell through to here.
|
// or return equal if we fell through to here.
|
||||||
__ ret(0); // rax, rdx were pushed
|
__ ret(0); // rax, rdx were pushed
|
||||||
__ bind(¬_both_objects);
|
|
||||||
}
|
}
|
||||||
|
__ bind(&runtime_call);
|
||||||
|
|
||||||
// Push arguments below the return address.
|
// Push arguments below the return address.
|
||||||
__ pop(ecx);
|
__ pop(ecx);
|
||||||
@ -1594,7 +1606,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
if (cc == equal) {
|
if (cc == equal) {
|
||||||
builtin = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
|
builtin = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
|
||||||
} else {
|
} else {
|
||||||
builtin = Builtins::COMPARE;
|
builtin = strong() ? Builtins::COMPARE_STRONG : Builtins::COMPARE;
|
||||||
__ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
|
__ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3300,7 +3312,7 @@ void CompareICStub::GenerateNumbers(MacroAssembler* masm) {
|
|||||||
|
|
||||||
__ bind(&unordered);
|
__ bind(&unordered);
|
||||||
__ bind(&generic_stub);
|
__ bind(&generic_stub);
|
||||||
CompareICStub stub(isolate(), op(), CompareICState::GENERIC,
|
CompareICStub stub(isolate(), op(), strong(), CompareICState::GENERIC,
|
||||||
CompareICState::GENERIC, CompareICState::GENERIC);
|
CompareICState::GENERIC, CompareICState::GENERIC);
|
||||||
__ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
|
__ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
|
||||||
|
|
||||||
|
@ -988,8 +988,8 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
|
|||||||
|
|
||||||
// Record position before stub call for type feedback.
|
// Record position before stub call for type feedback.
|
||||||
SetSourcePosition(clause->position());
|
SetSourcePosition(clause->position());
|
||||||
Handle<Code> ic =
|
Handle<Code> ic = CodeFactory::CompareIC(isolate(), Token::EQ_STRICT,
|
||||||
CodeFactory::CompareIC(isolate(), Token::EQ_STRICT).code();
|
language_mode()).code();
|
||||||
CallIC(ic, clause->CompareId());
|
CallIC(ic, clause->CompareId());
|
||||||
patch_site.EmitPatchInfo();
|
patch_site.EmitPatchInfo();
|
||||||
|
|
||||||
@ -5151,7 +5151,8 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
|
|||||||
|
|
||||||
// Record position and call the compare IC.
|
// Record position and call the compare IC.
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position());
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic =
|
||||||
|
CodeFactory::CompareIC(isolate(), op, language_mode()).code();
|
||||||
CallIC(ic, expr->CompareOperationFeedbackId());
|
CallIC(ic, expr->CompareOperationFeedbackId());
|
||||||
patch_site.EmitPatchInfo();
|
patch_site.EmitPatchInfo();
|
||||||
|
|
||||||
|
@ -2779,7 +2779,7 @@ static Condition ComputeCompareCondition(Token::Value op) {
|
|||||||
void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
|
void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
|
||||||
Token::Value op = instr->op();
|
Token::Value op = instr->op();
|
||||||
|
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op, SLOPPY).code();
|
||||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||||
|
|
||||||
Condition condition = ComputeCompareCondition(op);
|
Condition condition = ComputeCompareCondition(op);
|
||||||
@ -3051,7 +3051,8 @@ void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
|
|||||||
void LCodeGen::DoCmpT(LCmpT* instr) {
|
void LCodeGen::DoCmpT(LCmpT* instr) {
|
||||||
Token::Value op = instr->op();
|
Token::Value op = instr->op();
|
||||||
|
|
||||||
Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
|
Handle<Code> ic =
|
||||||
|
CodeFactory::CompareIC(isolate(), op, instr->language_mode()).code();
|
||||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||||
|
|
||||||
Condition condition = ComputeCompareCondition(op);
|
Condition condition = ComputeCompareCondition(op);
|
||||||
|
@ -1202,6 +1202,8 @@ class LCmpT final : public LTemplateInstruction<1, 3, 0> {
|
|||||||
DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
|
DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
|
||||||
DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
|
DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
|
||||||
|
|
||||||
|
LanguageMode language_mode() { return hydrogen()->language_mode(); }
|
||||||
|
|
||||||
LOperand* context() { return inputs_[0]; }
|
LOperand* context() { return inputs_[0]; }
|
||||||
Token::Value op() const { return hydrogen()->token(); }
|
Token::Value op() const { return hydrogen()->token(); }
|
||||||
};
|
};
|
||||||
|
@ -688,18 +688,20 @@ TEST_WITH_STRONG(MixedComparison1) {
|
|||||||
for (size_t j = 0; j < arraysize(types); j++) {
|
for (size_t j = 0; j < arraysize(types); j++) {
|
||||||
Node* p1 = R.Parameter(types[j], 1);
|
Node* p1 = R.Parameter(types[j], 1);
|
||||||
{
|
{
|
||||||
Node* cmp = R.Binop(R.javascript.LessThan(language_mode), p0, p1);
|
const Operator* less_than = R.javascript.LessThan(language_mode);
|
||||||
|
Node* cmp = R.Binop(less_than, p0, p1);
|
||||||
Node* r = R.reduce(cmp);
|
Node* r = R.reduce(cmp);
|
||||||
|
|
||||||
if (!types[i]->Maybe(Type::String()) ||
|
|
||||||
!types[j]->Maybe(Type::String())) {
|
|
||||||
if (types[i]->Is(Type::String()) && types[j]->Is(Type::String())) {
|
if (types[i]->Is(Type::String()) && types[j]->Is(Type::String())) {
|
||||||
R.CheckPureBinop(R.simplified.StringLessThan(), r);
|
R.CheckPureBinop(R.simplified.StringLessThan(), r);
|
||||||
} else {
|
} else if ((types[i]->Is(Type::Number()) &&
|
||||||
|
types[j]->Is(Type::Number())) ||
|
||||||
|
(!is_strong(language_mode) &&
|
||||||
|
(!types[i]->Maybe(Type::String()) ||
|
||||||
|
!types[j]->Maybe(Type::String())))) {
|
||||||
R.CheckPureBinop(R.simplified.NumberLessThan(), r);
|
R.CheckPureBinop(R.simplified.NumberLessThan(), r);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
CHECK_EQ(cmp, r); // No reduction of mixed types.
|
// No reduction of mixed types.
|
||||||
|
CHECK_EQ(r->op(), less_than);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
// Number function declarations
|
||||||
function inline_add_strong(x, y) {
|
function inline_add_strong(x, y) {
|
||||||
"use strong";
|
"use strong";
|
||||||
return x + y;
|
return x + y;
|
||||||
@ -105,6 +107,42 @@ function inline_sar_strong_outer(x, y) {
|
|||||||
return inline_sar_strong(x, y);
|
return inline_sar_strong(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function inline_less_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return x < y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_less_strong_outer(x, y) {
|
||||||
|
return inline_less_strong(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_greater_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return x > y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_greater_strong_outer(x, y) {
|
||||||
|
return inline_greater_strong(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_less_equal_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return x <= y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_less_equal_strong_outer(x, y) {
|
||||||
|
return inline_less_equal_strong(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_greater_equal_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return x >= y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_greater_equal_strong_outer(x, y) {
|
||||||
|
return inline_greater_equal_strong(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
function inline_add(x, y) {
|
function inline_add(x, y) {
|
||||||
return x + y;
|
return x + y;
|
||||||
}
|
}
|
||||||
@ -204,19 +242,170 @@ function inline_sar_outer_strong(x, y) {
|
|||||||
return inline_sar(x, y);
|
return inline_sar(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
let strong_inner_funcs = [inline_add_strong_outer, inline_sub_strong_outer,
|
function inline_less(x, y) {
|
||||||
|
return x < y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_less_outer_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return inline_less(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_greater(x, y) {
|
||||||
|
return x > y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_greater_outer_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return inline_greater(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_less_equal(x, y) {
|
||||||
|
return x <= y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_less_equal_outer_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return inline_less_equal(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_greater_equal(x, y) {
|
||||||
|
return x >>> y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_greater_equal_outer_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return inline_greater_equal(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
// String function declarations
|
||||||
|
function inline_add_string_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return x + y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_add_string_strong_outer(x, y) {
|
||||||
|
return inline_add_string_strong(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_less_string_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return x < y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_less_string_strong_outer(x, y) {
|
||||||
|
return inline_less_string_strong(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_greater_string_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return x > y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_greater_string_strong_outer(x, y) {
|
||||||
|
return inline_greater_string_strong(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_less_equal_string_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return x <= y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_less_equal_string_strong_outer(x, y) {
|
||||||
|
return inline_less_equal_string_strong(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_greater_equal_string_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return x >= y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_greater_equal_string_strong_outer(x, y) {
|
||||||
|
return inline_greater_equal_string_strong(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_add_string(x, y) {
|
||||||
|
return x + y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_add_string_outer_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return inline_add_string(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_less_string(x, y) {
|
||||||
|
return x < y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_less_string_outer_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return inline_less_string(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_greater_string(x, y) {
|
||||||
|
return x > y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_greater_string_outer_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return inline_greater_string(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_less_equal_string(x, y) {
|
||||||
|
return x <= y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_less_equal_string_outer_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return inline_less_equal_string(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_greater_equal_string(x, y) {
|
||||||
|
return x >= y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inline_greater_equal_string_outer_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return inline_greater_equal_string(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
// Testing
|
||||||
|
let strong_inner_funcs_num = [inline_add_strong_outer, inline_sub_strong_outer,
|
||||||
inline_mul_strong_outer, inline_div_strong_outer,
|
inline_mul_strong_outer, inline_div_strong_outer,
|
||||||
inline_mod_strong_outer, inline_or_strong_outer,
|
inline_mod_strong_outer, inline_or_strong_outer,
|
||||||
inline_and_strong_outer, inline_xor_strong_outer,
|
inline_and_strong_outer, inline_xor_strong_outer,
|
||||||
inline_shl_strong_outer, inline_shr_strong_outer];
|
inline_shl_strong_outer, inline_shr_strong_outer,
|
||||||
|
inline_less_strong_outer,
|
||||||
|
inline_greater_strong_outer,
|
||||||
|
inline_less_equal_strong_outer,
|
||||||
|
inline_greater_equal_strong_outer];
|
||||||
|
|
||||||
let strong_outer_funcs = [inline_add_outer_strong, inline_sub_outer_strong,
|
let strong_outer_funcs_num = [inline_add_outer_strong, inline_sub_outer_strong,
|
||||||
inline_mul_outer_strong, inline_div_outer_strong,
|
inline_mul_outer_strong, inline_div_outer_strong,
|
||||||
inline_mod_outer_strong, inline_or_outer_strong,
|
inline_mod_outer_strong, inline_or_outer_strong,
|
||||||
inline_and_outer_strong, inline_xor_outer_strong,
|
inline_and_outer_strong, inline_xor_outer_strong,
|
||||||
inline_shl_outer_strong, inline_shr_outer_strong];
|
inline_shl_outer_strong, inline_shr_outer_strong,
|
||||||
|
inline_less_outer_strong,
|
||||||
|
inline_greater_outer_strong,
|
||||||
|
inline_less_equal_outer_strong,
|
||||||
|
inline_greater_equal_outer_strong];
|
||||||
|
|
||||||
for (let strong_inner_func of strong_inner_funcs) {
|
let strong_inner_funcs_string = [inline_add_string_strong_outer,
|
||||||
|
inline_less_string_strong_outer,
|
||||||
|
inline_greater_string_strong_outer,
|
||||||
|
inline_less_equal_string_strong_outer,
|
||||||
|
inline_greater_equal_string_strong_outer];
|
||||||
|
|
||||||
|
let strong_outer_funcs_string = [inline_add_string_outer_strong,
|
||||||
|
inline_less_string_outer_strong,
|
||||||
|
inline_greater_string_outer_strong,
|
||||||
|
inline_less_equal_string_outer_strong,
|
||||||
|
inline_greater_equal_string_outer_strong];
|
||||||
|
|
||||||
|
for (let strong_inner_func of strong_inner_funcs_num) {
|
||||||
assertThrows(function(){strong_inner_func(1, {})}, TypeError);
|
assertThrows(function(){strong_inner_func(1, {})}, TypeError);
|
||||||
for (var i = 0; i < 100; i++) {
|
for (var i = 0; i < 100; i++) {
|
||||||
strong_inner_func(1, 2);
|
strong_inner_func(1, 2);
|
||||||
@ -225,7 +414,7 @@ for (let strong_inner_func of strong_inner_funcs) {
|
|||||||
assertThrows(function(){strong_inner_func(1, {})}, TypeError);
|
assertThrows(function(){strong_inner_func(1, {})}, TypeError);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let strong_outer_func of strong_outer_funcs) {
|
for (let strong_outer_func of strong_outer_funcs_num) {
|
||||||
assertDoesNotThrow(function(){strong_outer_func(1, {})});
|
assertDoesNotThrow(function(){strong_outer_func(1, {})});
|
||||||
for (var i = 0; i < 100; i++) {
|
for (var i = 0; i < 100; i++) {
|
||||||
strong_outer_func(1, 2);
|
strong_outer_func(1, 2);
|
||||||
@ -233,3 +422,21 @@ for (let strong_outer_func of strong_outer_funcs) {
|
|||||||
%OptimizeFunctionOnNextCall(strong_outer_func);
|
%OptimizeFunctionOnNextCall(strong_outer_func);
|
||||||
assertDoesNotThrow(function(){strong_outer_func(1, {})});
|
assertDoesNotThrow(function(){strong_outer_func(1, {})});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (let strong_inner_func of strong_inner_funcs_string) {
|
||||||
|
assertThrows(function(){strong_inner_func("foo", {})}, TypeError);
|
||||||
|
for (var i = 0; i < 100; i++) {
|
||||||
|
strong_inner_func("foo", "bar");
|
||||||
|
}
|
||||||
|
%OptimizeFunctionOnNextCall(strong_inner_func);
|
||||||
|
assertThrows(function(){strong_inner_func("foo", {})}, TypeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let strong_outer_func of strong_outer_funcs_string) {
|
||||||
|
assertDoesNotThrow(function(){strong_outer_func("foo", {})});
|
||||||
|
for (var i = 0; i < 100; i++) {
|
||||||
|
strong_outer_func("foo", "bar");
|
||||||
|
}
|
||||||
|
%OptimizeFunctionOnNextCall(strong_outer_func);
|
||||||
|
assertDoesNotThrow(function(){strong_outer_func("foo", {})});
|
||||||
|
}
|
||||||
|
@ -6,22 +6,26 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// TODO(conradw): Implement other strong operators
|
// Boolean indicates whether an operator can be part of a compound assignment.
|
||||||
let strongNumberBinops = [
|
let strongNumberBinops = [
|
||||||
"-",
|
["-", true],
|
||||||
"*",
|
["*", true],
|
||||||
"/",
|
["/", true],
|
||||||
"%",
|
["%", true],
|
||||||
"|",
|
["|", true],
|
||||||
"&",
|
["&", true],
|
||||||
"^",
|
["^", true],
|
||||||
"<<",
|
["<<", true],
|
||||||
">>",
|
[">>", true],
|
||||||
">>>",
|
[">>>", true]
|
||||||
];
|
];
|
||||||
|
|
||||||
let strongStringOrNumberBinops = [
|
let strongStringOrNumberBinops = [
|
||||||
"+"
|
["+", true],
|
||||||
|
["<", false],
|
||||||
|
[">", false],
|
||||||
|
["<=", false],
|
||||||
|
[">=", false]
|
||||||
];
|
];
|
||||||
|
|
||||||
let strongBinops = strongNumberBinops.concat(strongStringOrNumberBinops);
|
let strongBinops = strongNumberBinops.concat(strongStringOrNumberBinops);
|
||||||
@ -33,6 +37,8 @@ let strongUnops = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
let nonStringOrNumberValues = [
|
let nonStringOrNumberValues = [
|
||||||
|
"null",
|
||||||
|
"undefined",
|
||||||
"{}",
|
"{}",
|
||||||
"false",
|
"false",
|
||||||
"(function(){})",
|
"(function(){})",
|
||||||
@ -132,6 +138,46 @@ function sar_strong(x, y) {
|
|||||||
return x >>> y;
|
return x >>> y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function less_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return x < y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function less_num_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return x < y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function greater_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return x > y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function greater_num_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return x > y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function less_equal_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return x <= y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function less_equal_num_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return x <= y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function greater_equal_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return x >= y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function greater_equal_num_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return x >= y;
|
||||||
|
}
|
||||||
|
|
||||||
function typed_add_strong(x, y) {
|
function typed_add_strong(x, y) {
|
||||||
"use strong";
|
"use strong";
|
||||||
return (+x) + (+y);
|
return (+x) + (+y);
|
||||||
@ -187,15 +233,40 @@ function typed_sar_strong(x, y) {
|
|||||||
return (+x) >>> (+y);
|
return (+x) >>> (+y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function typed_less_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return (+x) < (+y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function typed_greater_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return (+x) > (+y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function typed_less_equal_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return (+x) <= (+y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function typed_greater_equal_strong(x, y) {
|
||||||
|
"use strong";
|
||||||
|
return (+x) >= (+y);
|
||||||
|
}
|
||||||
|
|
||||||
let strongNumberFuncs = [add_num_strong, sub_strong, mul_strong, div_strong,
|
let strongNumberFuncs = [add_num_strong, sub_strong, mul_strong, div_strong,
|
||||||
mod_strong, or_strong, and_strong, xor_strong,
|
mod_strong, or_strong, and_strong, xor_strong,
|
||||||
shl_strong, shr_strong, sar_strong, typed_add_strong,
|
shl_strong, shr_strong, sar_strong, less_num_strong,
|
||||||
|
greater_num_strong, less_equal_num_strong,
|
||||||
|
greater_equal_num_strong, typed_add_strong,
|
||||||
typed_sub_strong, typed_mul_strong, typed_div_strong,
|
typed_sub_strong, typed_mul_strong, typed_div_strong,
|
||||||
typed_mod_strong, typed_or_strong, typed_and_strong,
|
typed_mod_strong, typed_or_strong, typed_and_strong,
|
||||||
typed_xor_strong, typed_shl_strong, typed_shr_strong,
|
typed_xor_strong, typed_shl_strong, typed_shr_strong,
|
||||||
typed_sar_strong];
|
typed_sar_strong, typed_less_strong,
|
||||||
|
typed_greater_strong, typed_less_equal_strong,
|
||||||
|
typed_greater_equal_strong];
|
||||||
|
|
||||||
let strongStringOrNumberFuncs = [add_strong];
|
let strongStringOrNumberFuncs = [add_strong, less_strong, greater_strong,
|
||||||
|
less_equal_strong, greater_equal_strong];
|
||||||
|
|
||||||
let strongFuncs = strongNumberFuncs.concat(strongStringOrNumberFuncs);
|
let strongFuncs = strongNumberFuncs.concat(strongStringOrNumberFuncs);
|
||||||
|
|
||||||
@ -214,16 +285,20 @@ function assertStrongThrowBehaviour(expr) {
|
|||||||
|
|
||||||
function checkArgumentCombinations(op, leftList, rightList, willThrow) {
|
function checkArgumentCombinations(op, leftList, rightList, willThrow) {
|
||||||
for (let v1 of leftList) {
|
for (let v1 of leftList) {
|
||||||
let assignExpr = "foo " + op + "= " + v1 + ";";
|
let assignExpr = "foo " + op[0] + "= " + v1 + ";";
|
||||||
for (let v2 of rightList) {
|
for (let v2 of rightList) {
|
||||||
let compoundAssignment = "'use strong'; let foo = " + v2 + "; " +
|
let compoundAssignment = "'use strong'; let foo = " + v2 + "; " +
|
||||||
assignExpr;
|
assignExpr;
|
||||||
if (willThrow) {
|
if (willThrow) {
|
||||||
|
if (op[1]) {
|
||||||
assertThrows(compoundAssignment, TypeError);
|
assertThrows(compoundAssignment, TypeError);
|
||||||
assertStrongThrowBehaviour("(" + v1 + op + v2 + ")");
|
}
|
||||||
|
assertStrongThrowBehaviour("(" + v1 + op[0] + v2 + ")");
|
||||||
} else {
|
} else {
|
||||||
|
if (op[1]) {
|
||||||
assertDoesNotThrow(compoundAssignment);
|
assertDoesNotThrow(compoundAssignment);
|
||||||
assertStrongNonThrowBehaviour("(" + v1 + op + v2 + ")");
|
}
|
||||||
|
assertStrongNonThrowBehaviour("(" + v1 + op[0] + v2 + ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user