diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc index dc4592f791..2165f4c51f 100644 --- a/src/arm/codegen-arm.cc +++ b/src/arm/codegen-arm.cc @@ -3978,28 +3978,35 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) { } else if (check->Equals(Heap::function_symbol())) { __ tst(r1, Operand(kSmiTagMask)); false_target()->Branch(eq); - __ CompareObjectType(r1, r1, r1, JS_FUNCTION_TYPE); + Register map_reg = r2; + __ CompareObjectType(r1, map_reg, r1, JS_FUNCTION_TYPE); + true_target()->Branch(eq); + // Regular expressions are callable so typeof == 'function'. + __ CompareInstanceType(map_reg, r1, JS_REGEXP_TYPE); cc_reg_ = eq; } else if (check->Equals(Heap::object_symbol())) { __ tst(r1, Operand(kSmiTagMask)); false_target()->Branch(eq); - __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); __ LoadRoot(ip, Heap::kNullValueRootIndex); __ cmp(r1, ip); true_target()->Branch(eq); + Register map_reg = r2; + __ CompareObjectType(r1, map_reg, r1, JS_REGEXP_TYPE); + false_target()->Branch(eq); + // It can be an undetectable object. - __ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset)); + __ ldrb(r1, FieldMemOperand(map_reg, Map::kBitFieldOffset)); __ and_(r1, r1, Operand(1 << Map::kIsUndetectable)); __ cmp(r1, Operand(1 << Map::kIsUndetectable)); false_target()->Branch(eq); - __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); - __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE)); + __ ldrb(r1, FieldMemOperand(map_reg, Map::kInstanceTypeOffset)); + __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE)); false_target()->Branch(lt); - __ cmp(r2, Operand(LAST_JS_OBJECT_TYPE)); + __ cmp(r1, Operand(LAST_JS_OBJECT_TYPE)); cc_reg_ = le; } else { diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc index d49718bfc6..a3b5570848 100644 --- a/src/ia32/codegen-ia32.cc +++ b/src/ia32/codegen-ia32.cc @@ -5777,6 +5777,9 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) { destination()->false_target()->Branch(zero); frame_->Spill(answer.reg()); __ CmpObjectType(answer.reg(), JS_FUNCTION_TYPE, answer.reg()); + destination()->true_target()->Branch(equal); + // Regular expressions are callable so typeof == 'function'. + __ CmpInstanceType(answer.reg(), JS_REGEXP_TYPE); answer.Unuse(); destination()->Split(equal); @@ -5786,10 +5789,13 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) { __ cmp(answer.reg(), Factory::null_value()); destination()->true_target()->Branch(equal); - // It can be an undetectable object. Result map = allocator()->Allocate(); ASSERT(map.is_valid()); - __ mov(map.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); + // Regular expressions are typeof == 'function', not 'object'. + __ CmpObjectType(answer.reg(), JS_REGEXP_TYPE, map.reg()); + destination()->false_target()->Branch(equal); + + // It can be an undetectable object. __ movzx_b(map.reg(), FieldOperand(map.reg(), Map::kBitFieldOffset)); __ test(map.reg(), Immediate(1 << Map::kIsUndetectable)); destination()->false_target()->Branch(not_zero); diff --git a/src/macros.py b/src/macros.py index ddd2f13bc1..d6a2426c5a 100644 --- a/src/macros.py +++ b/src/macros.py @@ -77,12 +77,13 @@ const kMonthShift = 5; macro IS_NULL(arg) = (arg === null); macro IS_NULL_OR_UNDEFINED(arg) = (arg == null); macro IS_UNDEFINED(arg) = (typeof(arg) === 'undefined'); -macro IS_FUNCTION(arg) = (typeof(arg) === 'function'); macro IS_NUMBER(arg) = (typeof(arg) === 'number'); macro IS_STRING(arg) = (typeof(arg) === 'string'); -macro IS_OBJECT(arg) = (typeof(arg) === 'object'); +macro IS_OBJECT(arg) = (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp'); macro IS_BOOLEAN(arg) = (typeof(arg) === 'boolean'); macro IS_ARRAY(arg) = (%_IsArray(arg)); +# IS_FUNCTION uses %_ClassOf rather than typeof so as to exclude regexps. +macro IS_FUNCTION(arg) = (%_ClassOf(arg) === 'Function'); macro IS_REGEXP(arg) = (%_ClassOf(arg) === 'RegExp'); macro IS_DATE(arg) = (%_ClassOf(arg) === 'Date'); macro IS_NUMBER_WRAPPER(arg) = (%_ClassOf(arg) === 'Number'); diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc index d65960a997..210076dca2 100644 --- a/src/x64/codegen-x64.cc +++ b/src/x64/codegen-x64.cc @@ -3495,6 +3495,9 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) { destination()->false_target()->Branch(is_smi); frame_->Spill(answer.reg()); __ CmpObjectType(answer.reg(), JS_FUNCTION_TYPE, answer.reg()); + destination()->true_target()->Branch(equal); + // Regular expressions are callable so typeof == 'function'. + __ CmpInstanceType(answer.reg(), JS_REGEXP_TYPE); answer.Unuse(); destination()->Split(equal); @@ -3504,9 +3507,11 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) { __ CompareRoot(answer.reg(), Heap::kNullValueRootIndex); destination()->true_target()->Branch(equal); + // Regular expressions are typeof == 'function', not 'object'. + __ CmpObjectType(answer.reg(), JS_REGEXP_TYPE, kScratchRegister); + destination()->false_target()->Branch(equal); + // It can be an undetectable object. - __ movq(kScratchRegister, - FieldOperand(answer.reg(), HeapObject::kMapOffset)); __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), Immediate(1 << Map::kIsUndetectable)); destination()->false_target()->Branch(not_zero); diff --git a/test/mjsunit/mjsunit.js b/test/mjsunit/mjsunit.js index 1fb3f02afb..8ced0119fe 100644 --- a/test/mjsunit/mjsunit.js +++ b/test/mjsunit/mjsunit.js @@ -75,6 +75,9 @@ function deepEquals(a, b) { if (typeof a == "number" && typeof b == "number" && isNaN(a) && isNaN(b)) { return true; } + if (a.constructor === RegExp || b.constructor === RegExp) { + return (a.constructor === b.constructor) && (a.toString === b.toString); + } if ((typeof a) !== 'object' || (typeof b) !== 'object' || (a === null) || (b === null)) return false;