Diff
Modified: trunk/JSTests/ChangeLog (228967 => 228968)
--- trunk/JSTests/ChangeLog 2018-02-23 23:26:40 UTC (rev 228967)
+++ trunk/JSTests/ChangeLog 2018-02-24 00:48:32 UTC (rev 228968)
@@ -1,3 +1,12 @@
+2018-02-23 Saam Barati <sbar...@apple.com>
+
+ Make Number.isInteger an intrinsic
+ https://bugs.webkit.org/show_bug.cgi?id=183088
+
+ Reviewed by JF Bastien.
+
+ * stress/number-is-integer-intrinsic.js: Added.
+
2018-02-23 Oleksandr Skachkov <gskach...@gmail.com>
WebAssembly: cache memory address / size on instance
Added: trunk/JSTests/stress/number-is-integer-intrinsic.js (0 => 228968)
--- trunk/JSTests/stress/number-is-integer-intrinsic.js (rev 0)
+++ trunk/JSTests/stress/number-is-integer-intrinsic.js 2018-02-24 00:48:32 UTC (rev 228968)
@@ -0,0 +1,72 @@
+function assert(b) {
+ if (!b)
+ throw new Error;
+}
+
+function onlyDouble(x) {
+ return Number.isInteger(x);
+}
+noInline(onlyDouble);
+
+let interestingValues = [
+ [Infinity, false],
+ [-Infinity, false],
+ [NaN, false],
+ [0.0, true],
+ [-0.0, true],
+ [90071992547490009021129120, true],
+ [9007199254749001000, true],
+ [Number.MAX_SAFE_INTEGER, true],
+ [Number.MIN_SAFE_INTEGER, true],
+ [0.5, false],
+ [Math.PI, false],
+ [42, true],
+ [0, true],
+ [-10, true],
+ [2147483647, true],
+ [-2147483648, true],
+ [Number.MIN_VALUE, false],
+ [Number.MAX_VALUE, true],
+ [-Number.MAX_VALUE, true],
+];
+
+for (let i = 0; i < 10000; ++i) {
+ for (let [value, result] of interestingValues) {
+ assert(onlyDouble(value) === result);
+ }
+}
+
+interestingValues.push(
+ [true, false],
+ [false, false],
+ [undefined, false],
+ [null, false],
+ [{}, false],
+ [{valueOf() { throw new Error("Should not be called"); }}, false],
+ [function(){}, false],
+);
+
+function generic(x) {
+ return Number.isInteger(x);
+}
+noInline(generic);
+
+for (let i = 0; i < 10000; ++i) {
+ for (let [value, result] of interestingValues) {
+ assert(generic(value) === result);
+ }
+}
+
+function onlyInts(x) {
+ return Number.isInteger(x);
+}
+noInline(onlyInts);
+
+for (let i = 0; i < 10000; ++i) {
+ assert(onlyInts(i) === true);
+}
+for (let i = 0; i < 10000; ++i) {
+ for (let [value, result] of interestingValues) {
+ assert(onlyInts(value) === result);
+ }
+}
Modified: trunk/Source/_javascript_Core/ChangeLog (228967 => 228968)
--- trunk/Source/_javascript_Core/ChangeLog 2018-02-23 23:26:40 UTC (rev 228967)
+++ trunk/Source/_javascript_Core/ChangeLog 2018-02-24 00:48:32 UTC (rev 228968)
@@ -1,3 +1,52 @@
+2018-02-23 Saam Barati <sbar...@apple.com>
+
+ Make Number.isInteger an intrinsic
+ https://bugs.webkit.org/show_bug.cgi?id=183088
+
+ Reviewed by JF Bastien.
+
+ When profiling the ML subtest in ARES, I noticed it was spending some
+ time in Number.isInteger. This patch makes that operation an intrinsic
+ in the DFG/FTL. It might be a speedup by 1% or so on that subtest, but
+ it's likely not an aggregate speedup on ARES. However, it is definitely
+ faster than calling into a builtin function, so we might as well have
+ it as an intrinsic.
+
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
+ * dfg/DFGClobberize.h:
+ (JSC::DFG::clobberize):
+ * dfg/DFGDoesGC.cpp:
+ (JSC::DFG::doesGC):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGNodeType.h:
+ * dfg/DFGOperations.cpp:
+ * dfg/DFGOperations.h:
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ * dfg/DFGSafeToExecute.h:
+ (JSC::DFG::safeToExecute):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * ftl/FTLCapabilities.cpp:
+ (JSC::FTL::canCompile):
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+ (JSC::FTL::DFG::LowerDFGToB3::compileNumberIsInteger):
+ (JSC::FTL::DFG::LowerDFGToB3::unboxDouble):
+ * runtime/Intrinsic.cpp:
+ (JSC::intrinsicName):
+ * runtime/Intrinsic.h:
+ * runtime/NumberConstructor.cpp:
+ (JSC::NumberConstructor::finishCreation):
+ (JSC::numberConstructorFuncIsInteger):
+ * runtime/NumberConstructor.h:
+ (JSC::NumberConstructor::isIntegerImpl):
+
2018-02-23 Oleksandr Skachkov <gskach...@gmail.com>
WebAssembly: cache memory address / size on instance
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (228967 => 228968)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2018-02-23 23:26:40 UTC (rev 228967)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2018-02-24 00:48:32 UTC (rev 228968)
@@ -36,6 +36,7 @@
#include "HashMapImpl.h"
#include "JITOperations.h"
#include "MathCommon.h"
+#include "NumberConstructor.h"
#include "Operations.h"
#include "PutByIdStatus.h"
#include "StringObject.h"
@@ -1176,6 +1177,7 @@
case IsUndefined:
case IsBoolean:
case IsNumber:
+ case NumberIsInteger:
case IsObject:
case IsObjectOrNull:
case IsFunction:
@@ -1200,6 +1202,9 @@
case IsNumber:
setConstant(node, jsBoolean(child.value().isNumber()));
break;
+ case NumberIsInteger:
+ setConstant(node, jsBoolean(NumberConstructor::isIntegerImpl(child.value())));
+ break;
case IsObject:
setConstant(node, jsBoolean(child.value().isObject()));
break;
@@ -1307,6 +1312,22 @@
}
break;
+
+ case NumberIsInteger:
+ if (!(child.m_type & ~SpecInt32Only)) {
+ setConstant(node, jsBoolean(true));
+ constantWasSet = true;
+ break;
+ }
+
+ if (!(child.m_type & SpecFullNumber)) {
+ setConstant(node, jsBoolean(false));
+ constantWasSet = true;
+ break;
+ }
+
+ break;
+
case IsObject:
if (!(child.m_type & ~SpecObject)) {
setConstant(node, jsBoolean(true));
Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (228967 => 228968)
--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2018-02-23 23:26:40 UTC (rev 228967)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2018-02-24 00:48:32 UTC (rev 228968)
@@ -3126,6 +3126,17 @@
return true;
}
+ case NumberIsIntegerIntrinsic: {
+ if (argumentCountIncludingThis < 2)
+ return false;
+
+ insertChecks();
+ Node* input = get(virtualRegisterForArgument(1, registerOffset));
+ Node* result = addToGraph(NumberIsInteger, input);
+ set(VirtualRegister(resultOperand), result);
+ return true;
+ }
+
case CPUMfenceIntrinsic:
case CPURdtscIntrinsic:
case CPUCpuidIntrinsic:
Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (228967 => 228968)
--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2018-02-23 23:26:40 UTC (rev 228967)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2018-02-24 00:48:32 UTC (rev 228968)
@@ -169,6 +169,7 @@
case IsUndefined:
case IsBoolean:
case IsNumber:
+ case NumberIsInteger:
case IsObject:
case IsTypedArrayView:
case LogicalNot:
Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (228967 => 228968)
--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2018-02-23 23:26:40 UTC (rev 228967)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2018-02-24 00:48:32 UTC (rev 228968)
@@ -174,6 +174,7 @@
case IsUndefined:
case IsBoolean:
case IsNumber:
+ case NumberIsInteger:
case IsObject:
case IsObjectOrNull:
case IsFunction:
Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (228967 => 228968)
--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2018-02-23 23:26:40 UTC (rev 228967)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2018-02-24 00:48:32 UTC (rev 228968)
@@ -2108,6 +2108,16 @@
fixEdge<StringUse>(node->child1());
break;
+ case NumberIsInteger:
+ if (node->child1()->shouldSpeculateInt32()) {
+ m_insertionSet.insertNode(
+ m_indexInBlock, SpecNone, Check, node->origin,
+ Edge(node->child1().node(), Int32Use));
+ m_graph.convertToConstant(node, jsBoolean(true));
+ break;
+ }
+ break;
+
#if !ASSERT_DISABLED
// Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes.
case SetArgument:
Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (228967 => 228968)
--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2018-02-23 23:26:40 UTC (rev 228967)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2018-02-24 00:48:32 UTC (rev 228968)
@@ -348,6 +348,7 @@
macro(IsUndefined, NodeResultBoolean) \
macro(IsBoolean, NodeResultBoolean) \
macro(IsNumber, NodeResultBoolean) \
+ macro(NumberIsInteger, NodeResultBoolean) \
macro(IsObject, NodeResultBoolean) \
macro(IsObjectOrNull, NodeResultBoolean) \
macro(IsFunction, NodeResultBoolean) \
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (228967 => 228968)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2018-02-23 23:26:40 UTC (rev 228967)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2018-02-24 00:48:32 UTC (rev 228968)
@@ -59,6 +59,7 @@
#include "JSSet.h"
#include "JSWeakMap.h"
#include "JSWeakSet.h"
+#include "NumberConstructor.h"
#include "ObjectConstructor.h"
#include "Operations.h"
#include "ParseInt.h"
@@ -2254,6 +2255,13 @@
return result;
}
+int32_t JIT_OPERATION operationNumberIsInteger(ExecState* exec, EncodedJSValue value)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+ return NumberConstructor::isIntegerImpl(JSValue::decode(value));
+}
+
int32_t JIT_OPERATION operationArrayIndexOfString(ExecState* exec, Butterfly* butterfly, JSString* searchElement, int32_t index)
{
VM& vm = exec->vm();
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (228967 => 228968)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.h 2018-02-23 23:26:40 UTC (rev 228967)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h 2018-02-24 00:48:32 UTC (rev 228968)
@@ -254,6 +254,8 @@
int64_t JIT_OPERATION operationConvertBoxedDoubleToInt52(EncodedJSValue);
int64_t JIT_OPERATION operationConvertDoubleToInt52(double);
+int32_t JIT_OPERATION operationNumberIsInteger(ExecState*, EncodedJSValue);
+
size_t JIT_OPERATION operationDefaultHasInstance(ExecState*, JSCell* value, JSCell* proto);
char* JIT_OPERATION operationNewRawObject(ExecState*, Structure*, int32_t, Butterfly*) WTF_INTERNAL;
Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (228967 => 228968)
--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2018-02-23 23:26:40 UTC (rev 228967)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2018-02-24 00:48:32 UTC (rev 228968)
@@ -849,6 +849,7 @@
case IsUndefined:
case IsBoolean:
case IsNumber:
+ case NumberIsInteger:
case IsObject:
case IsObjectOrNull:
case IsFunction:
Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (228967 => 228968)
--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2018-02-23 23:26:40 UTC (rev 228967)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2018-02-24 00:48:32 UTC (rev 228968)
@@ -306,6 +306,7 @@
case IsUndefined:
case IsBoolean:
case IsNumber:
+ case NumberIsInteger:
case IsObject:
case IsObjectOrNull:
case IsFunction:
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (228967 => 228968)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2018-02-23 23:26:40 UTC (rev 228967)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2018-02-24 00:48:32 UTC (rev 228968)
@@ -4405,6 +4405,17 @@
break;
}
+ case NumberIsInteger: {
+ JSValueOperand input(this, node->child1());
+ JSValueRegs inputRegs = input.jsValueRegs();
+ flushRegisters();
+ GPRFlushedCallResult result(this);
+ GPRReg resultGPR = result.gpr();
+ callOperation(operationNumberIsInteger, resultGPR, inputRegs);
+ booleanResult(resultGPR, node);
+ break;
+ }
+
case IsObject: {
JSValueOperand value(this, node->child1());
GPRTemporary result(this, Reuse, value, TagWord);
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (228967 => 228968)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2018-02-23 23:26:40 UTC (rev 228967)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2018-02-24 00:48:32 UTC (rev 228968)
@@ -4644,7 +4644,51 @@
jsValueResult(result.gpr(), node, DataFormatJSBoolean);
break;
}
-
+
+ case NumberIsInteger: {
+ JSValueOperand value(this, node->child1());
+ GPRTemporary result(this, Reuse, value);
+
+ FPRTemporary temp1(this);
+ FPRTemporary temp2(this);
+
+ JSValueRegs valueRegs = JSValueRegs(value.gpr());
+ GPRReg resultGPR = value.gpr();
+
+ FPRReg tempFPR1 = temp1.fpr();
+ FPRReg tempFPR2 = temp2.fpr();
+
+ MacroAssembler::JumpList done;
+
+ auto isInt32 = m_jit.branchIfInt32(valueRegs);
+ auto notNumber = m_jit.branchIfNotDoubleKnownNotInt32(valueRegs);
+
+ // We're a double here.
+ m_jit.unboxDouble(valueRegs.gpr(), resultGPR, tempFPR1);
+ m_jit.urshift64(TrustedImm32(52), resultGPR);
+ m_jit.and32(TrustedImm32(0x7ff), resultGPR);
+ auto notNanNorInfinity = m_jit.branch32(JITCompiler::NotEqual, TrustedImm32(0x7ff), resultGPR);
+ m_jit.move(TrustedImm32(ValueFalse), resultGPR);
+ done.append(m_jit.jump());
+
+ notNanNorInfinity.link(&m_jit);
+ m_jit.roundTowardZeroDouble(tempFPR1, tempFPR2);
+ m_jit.compareDouble(JITCompiler::DoubleEqual, tempFPR1, tempFPR2, resultGPR);
+ m_jit.or32(TrustedImm32(ValueFalse), resultGPR);
+ done.append(m_jit.jump());
+
+ isInt32.link(&m_jit);
+ m_jit.move(TrustedImm32(ValueTrue), resultGPR);
+ done.append(m_jit.jump());
+
+ notNumber.link(&m_jit);
+ m_jit.move(TrustedImm32(ValueFalse), resultGPR);
+
+ done.link(&m_jit);
+ jsValueResult(resultGPR, node, DataFormatJSBoolean);
+ break;
+ }
+
case MapHash: {
switch (node->child1().useKind()) {
case BooleanUse:
Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (228967 => 228968)
--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2018-02-23 23:26:40 UTC (rev 228967)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2018-02-24 00:48:32 UTC (rev 228968)
@@ -221,6 +221,7 @@
case IsUndefined:
case IsBoolean:
case IsNumber:
+ case NumberIsInteger:
case IsObject:
case IsObjectOrNull:
case IsFunction:
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (228967 => 228968)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2018-02-23 23:26:40 UTC (rev 228967)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2018-02-24 00:48:32 UTC (rev 228968)
@@ -1062,6 +1062,9 @@
case IsNumber:
compileIsNumber();
break;
+ case NumberIsInteger:
+ compileNumberIsInteger();
+ break;
case IsCellWithType:
compileIsCellWithType();
break;
@@ -8778,6 +8781,51 @@
{
setBoolean(isNumber(lowJSValue(m_node->child1()), provenType(m_node->child1())));
}
+
+ void compileNumberIsInteger()
+ {
+ LBasicBlock notInt32 = m_out.newBlock();
+ LBasicBlock doubleCase = m_out.newBlock();
+ LBasicBlock doubleNotNanOrInf = m_out.newBlock();
+ LBasicBlock continuation = m_out.newBlock();
+
+ LValue input = lowJSValue(m_node->child1());
+
+ ValueFromBlock trueResult = m_out.anchor(m_out.booleanTrue);
+ m_out.branch(
+ isInt32(input, provenType(m_node->child1())), unsure(continuation), unsure(notInt32));
+
+ LBasicBlock lastNext = m_out.appendTo(notInt32, doubleCase);
+ ValueFromBlock falseResult = m_out.anchor(m_out.booleanFalse);
+ m_out.branch(
+ isNotNumber(input, provenType(m_node->child1())), unsure(continuation), unsure(doubleCase));
+
+ m_out.appendTo(doubleCase, doubleNotNanOrInf);
+ LValue doubleAsInt;
+ LValue asDouble = unboxDouble(input, &doubleAsInt);
+ LValue expBits = m_out.bitAnd(m_out.lShr(doubleAsInt, m_out.constInt32(52)), m_out.constInt64(0x7ff));
+ m_out.branch(
+ m_out.equal(expBits, m_out.constInt64(0x7ff)),
+ unsure(continuation), unsure(doubleNotNanOrInf));
+
+ m_out.appendTo(doubleNotNanOrInf, continuation);
+ B3::PatchpointValue* patchpoint = m_out.patchpoint(Int32);
+ patchpoint->appendSomeRegister(asDouble);
+ patchpoint->numFPScratchRegisters = 1;
+ patchpoint->effects = Effects::none();
+ patchpoint->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+ GPRReg result = params[0].gpr();
+ FPRReg input = params[1].fpr();
+ FPRReg temp = params.fpScratch(0);
+ jit.roundTowardZeroDouble(input, temp);
+ jit.compareDouble(MacroAssembler::DoubleEqual, input, temp, result);
+ });
+ ValueFromBlock patchpointResult = m_out.anchor(patchpoint);
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
+ setBoolean(m_out.phi(Int32, trueResult, falseResult, patchpointResult));
+ }
void compileIsCellWithType()
{
@@ -14318,9 +14366,12 @@
return m_out.testNonZero64(jsValue, m_tagTypeNumber);
}
- LValue unboxDouble(LValue jsValue)
+ LValue unboxDouble(LValue jsValue, LValue* unboxedAsInt = nullptr)
{
- return m_out.bitCast(m_out.add(jsValue, m_tagTypeNumber), Double);
+ LValue asInt = m_out.add(jsValue, m_tagTypeNumber);
+ if (unboxedAsInt)
+ *unboxedAsInt = asInt;
+ return m_out.bitCast(asInt, Double);
}
LValue boxDouble(LValue doubleValue)
{
Modified: trunk/Source/_javascript_Core/runtime/Intrinsic.cpp (228967 => 228968)
--- trunk/Source/_javascript_Core/runtime/Intrinsic.cpp 2018-02-23 23:26:40 UTC (rev 228967)
+++ trunk/Source/_javascript_Core/runtime/Intrinsic.cpp 2018-02-24 00:48:32 UTC (rev 228968)
@@ -129,6 +129,8 @@
return "StringPrototypeToLowerCaseIntrinsic";
case NumberPrototypeToStringIntrinsic:
return "NumberPrototypeToStringIntrinsic";
+ case NumberIsIntegerIntrinsic:
+ return "NumberIsIntegerIntrinsic";
case IMulIntrinsic:
return "IMulIntrinsic";
case RandomIntrinsic:
Modified: trunk/Source/_javascript_Core/runtime/Intrinsic.h (228967 => 228968)
--- trunk/Source/_javascript_Core/runtime/Intrinsic.h 2018-02-23 23:26:40 UTC (rev 228967)
+++ trunk/Source/_javascript_Core/runtime/Intrinsic.h 2018-02-24 00:48:32 UTC (rev 228968)
@@ -77,6 +77,7 @@
StringPrototypeSliceIntrinsic,
StringPrototypeToLowerCaseIntrinsic,
NumberPrototypeToStringIntrinsic,
+ NumberIsIntegerIntrinsic,
IMulIntrinsic,
RandomIntrinsic,
FRoundIntrinsic,
Modified: trunk/Source/_javascript_Core/runtime/NumberConstructor.cpp (228967 => 228968)
--- trunk/Source/_javascript_Core/runtime/NumberConstructor.cpp 2018-02-23 23:26:40 UTC (rev 228967)
+++ trunk/Source/_javascript_Core/runtime/NumberConstructor.cpp 2018-02-24 00:48:32 UTC (rev 228968)
@@ -47,7 +47,6 @@
/* Source for NumberConstructor.lut.h
@begin numberConstructorTable
isFinite JSBuiltin DontEnum|Function 1
- isInteger numberConstructorFuncIsInteger DontEnum|Function 1
isNaN JSBuiltin DontEnum|Function 1
isSafeInteger numberConstructorFuncIsSafeInteger DontEnum|Function 1
@end
@@ -66,6 +65,8 @@
Base::finishCreation(vm, NumberPrototype::info()->className);
ASSERT(inherits(vm, info()));
+ JSGlobalObject* globalObject = numberPrototype->globalObject();
+
putDirectWithoutTransition(vm, vm.propertyNames->prototype, numberPrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum);
@@ -80,6 +81,8 @@
putDirectWithoutTransition(vm, vm.propertyNames->parseInt, numberPrototype->globalObject()->parseIntFunction(), static_cast<unsigned>(PropertyAttribute::DontEnum));
putDirectWithoutTransition(vm, vm.propertyNames->parseFloat, numberPrototype->globalObject()->parseFloatFunction(), static_cast<unsigned>(PropertyAttribute::DontEnum));
+
+ JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(Identifier::fromString(&vm, "isInteger"), numberConstructorFuncIsInteger, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, NumberIsIntegerIntrinsic);
}
// ECMA 15.7.1
@@ -106,17 +109,7 @@
// ECMA-262 20.1.2.3
static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsInteger(ExecState* exec)
{
- JSValue argument = exec->argument(0);
- bool isInteger;
- if (argument.isInt32())
- isInteger = true;
- else if (!argument.isDouble())
- isInteger = false;
- else {
- double number = argument.asDouble();
- isInteger = std::isfinite(number) && trunc(number) == number;
- }
- return JSValue::encode(jsBoolean(isInteger));
+ return JSValue::encode(jsBoolean(NumberConstructor::isIntegerImpl(exec->argument(0))));
}
// ECMA-262 20.1.2.5
Modified: trunk/Source/_javascript_Core/runtime/NumberConstructor.h (228967 => 228968)
--- trunk/Source/_javascript_Core/runtime/NumberConstructor.h 2018-02-23 23:26:40 UTC (rev 228967)
+++ trunk/Source/_javascript_Core/runtime/NumberConstructor.h 2018-02-24 00:48:32 UTC (rev 228968)
@@ -46,6 +46,17 @@
return Structure::create(vm, globalObject, proto, TypeInfo(InternalFunctionType, StructureFlags), info());
}
+ static bool isIntegerImpl(JSValue value)
+ {
+ if (value.isInt32())
+ return true;
+ if (!value.isDouble())
+ return false;
+
+ double number = value.asDouble();
+ return std::isfinite(number) && trunc(number) == number;
+ }
+
protected:
void finishCreation(VM&, NumberPrototype*);