Commit 6a95834c authored by darin@apple.com's avatar darin@apple.com

Reviewed by Oliver.

        - http://bugs.webkit.org/show_bug.cgi?id=15904
          more speed-ups possible by tightening up int version of JSImmediate

        1% improvement of SunSpider

        * kjs/JSImmediate.h: Eliminate the now-unneeded FPBitValues struct template.
        (KJS::JSImmediate::from): Overload for most numeric types; many types can
        do fewer branches and checks.
        (KJS::JSImmediate::getUInt32): Removed unneeded check for undefined.
        (KJS::JSImmediate::getTruncatedInt32): Ditto.
        (KJS::JSImmediate::getTruncatedUInt32): Ditto. There's no difference any more
        between getUInt32 and getTruncatedUInt32, so that's worth a rename and merge later.

        * kjs/grammar.y: Update since fromDouble is now just from.
        * kjs/nodes.h: Ditto.

        * kjs/value.h: (KJS::jsNumber): Overload for most numeric types.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@27632 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 56b2f6f1
2007-11-08 Darin Adler <darin@apple.com>
Reviewed by Oliver.
- http://bugs.webkit.org/show_bug.cgi?id=15904
more speed-ups possible by tightening up int version of JSImmediate
1% improvement of SunSpider
* kjs/JSImmediate.h: Eliminate the now-unneeded FPBitValues struct template.
(KJS::JSImmediate::from): Overload for most numeric types; many types can
do fewer branches and checks.
(KJS::JSImmediate::getUInt32): Removed unneeded check for undefined.
(KJS::JSImmediate::getTruncatedInt32): Ditto.
(KJS::JSImmediate::getTruncatedUInt32): Ditto. There's no difference any more
between getUInt32 and getTruncatedUInt32, so that's worth a rename and merge later.
* kjs/grammar.y: Update since fromDouble is now just from.
* kjs/nodes.h: Ditto.
* kjs/value.h: (KJS::jsNumber): Overload for most numeric types.
2007-11-08 Kevin Ollivier <kevino@theolliviers.com>
Bakefiles for building JavaScriptCore, needed by wx port.
......
......@@ -82,6 +82,19 @@ public:
return (getTag(v) == UndefinedType);
}
static JSValue* from(char);
static JSValue* from(signed char);
static JSValue* from(unsigned char);
static JSValue* from(short);
static JSValue* from(unsigned short);
static JSValue* from(int);
static JSValue* from(unsigned);
static JSValue* from(long);
static JSValue* from(unsigned long);
static JSValue* from(long long);
static JSValue* from(unsigned long long);
static JSValue* from(double);
static ALWAYS_INLINE bool areBothImmediateNumbers(const JSValue* v1, const JSValue* v2)
{
return (reinterpret_cast<uintptr_t>(v1) & reinterpret_cast<uintptr_t>(v2) & TagMask) == NumberType;
......@@ -93,7 +106,6 @@ public:
return reinterpret_cast<JSValue*>(reinterpret_cast<uintptr_t>(v1) & reinterpret_cast<uintptr_t>(v2));
}
static JSValue* fromDouble(double d);
static double toDouble(const JSValue*);
static bool toBoolean(const JSValue*);
static JSObject* toObject(const JSValue*, ExecState*);
......@@ -104,8 +116,6 @@ public:
static bool getTruncatedInt32(const JSValue*, int32_t&);
static bool getTruncatedUInt32(const JSValue*, uint32_t&);
// It would nice just to use fromDouble() to create these values, but that would prevent them from
// turning into compile-time constants.
static JSValue* trueImmediate();
static JSValue* falseImmediate();
static JSValue* undefinedImmediate();
......@@ -113,6 +123,11 @@ public:
private:
static const uintptr_t TagMask = 3; // type tags are 2 bits long
// Immediate values are restricted to a 30 bit signed value.
static const int minImmediateInt = -(1 << 29);
static const int maxImmediateInt = (1 << 29) - 1;
static const unsigned maxImmediateUInt = maxImmediateInt;
static ALWAYS_INLINE JSValue* tag(uintptr_t bits, uintptr_t tag)
{
......@@ -128,146 +143,126 @@ private:
{
return reinterpret_cast<uintptr_t>(v) & TagMask;
}
// we support 32-bit platforms with sizes like this
static const bool is32bit =
sizeof(float) == sizeof(uint32_t) && sizeof(double) == sizeof(uint64_t) && sizeof(uintptr_t) == sizeof(uint32_t);
};
// we support 64-bit platforms with sizes like this
static const bool is64bit =
sizeof(float) == sizeof(uint32_t) && sizeof(double) == sizeof(uint64_t) && sizeof(uintptr_t) == sizeof(uint64_t);
ALWAYS_INLINE JSValue* JSImmediate::trueImmediate() { return tag(1 << 2, BooleanType); }
ALWAYS_INLINE JSValue* JSImmediate::falseImmediate() { return tag(0, BooleanType); }
ALWAYS_INLINE JSValue* JSImmediate::undefinedImmediate() { return tag(1 << 2, UndefinedType); }
ALWAYS_INLINE JSValue* JSImmediate::nullImmediate() { return tag(0, UndefinedType); }
template<bool for32bit, bool for64bit> struct FPBitValues {};
};
ALWAYS_INLINE bool JSImmediate::toBoolean(const JSValue* v)
{
ASSERT(isImmediate(v));
uintptr_t bits = unTag(v);
return (bits != 0) & (JSImmediate::getTag(v) != UndefinedType);
}
template<> struct JSImmediate::FPBitValues<true, false> {
static const uint32_t nanAsBits = 0x7fc00000;
static const uint32_t oneAsBits = 0x3f800000;
static const uint32_t zeroAsBits = 0x0;
ALWAYS_INLINE JSValue* JSImmediate::from(char i)
{
return tag(i << 2, NumberType);
}
static ALWAYS_INLINE JSValue* fromDouble(double d)
{
const int32_t intVal = static_cast<int>(d);
// On 32 bit systems immediate values are restricted to a 30 bit signed value
if ((intVal <= -(1 << 29)) | (intVal >= ((1 << 29) - 1)))
return 0;
// Check for data loss from conversion to int. This
// will reject NaN, +/-Inf, and -0.
// Happily none of these are as common as raw int values
if ((intVal != d) || (signbit(d) && !intVal))
return 0;
return tag(intVal << 2, NumberType);
}
ALWAYS_INLINE JSValue* JSImmediate::from(signed char i)
{
return tag(i << 2, NumberType);
}
static ALWAYS_INLINE double toDouble(const JSValue* v)
{
ASSERT(isImmediate(v));
const int32_t i = static_cast<int32_t>(unTag(v)) >> 2;
if (JSImmediate::getTag(v) == UndefinedType && i)
return std::numeric_limits<double>::quiet_NaN();
return i;
}
static ALWAYS_INLINE bool getTruncatedInt32(const JSValue* v, int32_t& i)
{
i = static_cast<int32_t>(unTag(v)) >> 2;
if (JSImmediate::getTag(v) == UndefinedType && i)
return false;
return isNumber(v);
}
static ALWAYS_INLINE bool getTruncatedUInt32(const JSValue* v, uint32_t& i)
{
int32_t& si = reinterpret_cast<int&>(i);
return getTruncatedInt32(v, si) & (si >= 0);
}
};
ALWAYS_INLINE JSValue* JSImmediate::from(unsigned char i)
{
return tag(i << 2, NumberType);
}
template<> struct JSImmediate::FPBitValues<false, true> {
static const uint64_t nanAsBits = 0x7ff80000ULL << 32;
static const uint64_t oneAsBits = 0x3ff00000ULL << 32;
static const uint64_t zeroAsBits = 0x0;
ALWAYS_INLINE JSValue* JSImmediate::from(short i)
{
return tag(i << 2, NumberType);
}
static ALWAYS_INLINE JSValue* fromDouble(double d)
{
const int64_t intVal = static_cast<int>(d);
// Technically we could fit a 60 bit signed int here, however that would
// required more branches when extracting int values.
if ((intVal <= -(1L << 29)) | (intVal >= ((1 << 29) - 1)))
return 0;
// Check for data loss from conversion to int. This
// will reject NaN, +/-Inf, and -0.
// Happily none of these are as common as raw int values
if ((intVal != d) || (signbit(d) && !intVal))
return 0;
return tag(static_cast<uintptr_t>(intVal << 2), NumberType);
}
ALWAYS_INLINE JSValue* JSImmediate::from(unsigned short i)
{
return tag(i << 2, NumberType);
}
static ALWAYS_INLINE double toDouble(const JSValue* v)
{
ASSERT(isImmediate(v));
const int32_t i = static_cast<int32_t>(unTag(v) >> 2);
if (JSImmediate::getTag(v) == UndefinedType && i)
return std::numeric_limits<double>::quiet_NaN();
return i;
}
ALWAYS_INLINE JSValue* JSImmediate::from(int i)
{
if ((i < minImmediateInt) | (i > maxImmediateInt))
return 0;
return tag(i << 2, NumberType);
}
static ALWAYS_INLINE bool getTruncatedInt32(const JSValue* v, int32_t& i)
{
i = static_cast<int32_t>(unTag(v) >> 2);
if (JSImmediate::getTag(v) == UndefinedType && i)
return false;
return isNumber(v);
}
ALWAYS_INLINE JSValue* JSImmediate::from(unsigned i)
{
if (i > maxImmediateUInt)
return 0;
return tag(i << 2, NumberType);
}
static ALWAYS_INLINE bool getTruncatedUInt32(const JSValue* v, uint32_t& i)
{
int& si = reinterpret_cast<int&>(i);
return getTruncatedInt32(v, si) & (si >= 0);
}
};
ALWAYS_INLINE JSValue* JSImmediate::from(long i)
{
if ((i < minImmediateInt) | (i > maxImmediateInt))
return 0;
return tag(i << 2, NumberType);
}
ALWAYS_INLINE JSValue* JSImmediate::trueImmediate() { return tag(1 << 2, BooleanType); }
ALWAYS_INLINE JSValue* JSImmediate::falseImmediate() { return tag(0, BooleanType); }
ALWAYS_INLINE JSValue* JSImmediate::undefinedImmediate() { return tag(1 << 2, UndefinedType); }
ALWAYS_INLINE JSValue* JSImmediate::nullImmediate() { return tag(0, UndefinedType); }
ALWAYS_INLINE JSValue* JSImmediate::from(unsigned long i)
{
if (i > maxImmediateUInt)
return 0;
return tag(i << 2, NumberType);
}
ALWAYS_INLINE bool JSImmediate::toBoolean(const JSValue* v)
ALWAYS_INLINE JSValue* JSImmediate::from(long long i)
{
ASSERT(isImmediate(v));
uintptr_t bits = unTag(v);
return (bits != 0) & (JSImmediate::getTag(v) != UndefinedType);
if ((i < minImmediateInt) | (i > maxImmediateInt))
return 0;
return tag(static_cast<uintptr_t>(i) << 2, NumberType);
}
ALWAYS_INLINE JSValue* JSImmediate::from(unsigned long long i)
{
if (i > maxImmediateUInt)
return 0;
return tag(static_cast<uintptr_t>(i) << 2, NumberType);
}
ALWAYS_INLINE JSValue* JSImmediate::fromDouble(double d)
ALWAYS_INLINE JSValue* JSImmediate::from(double d)
{
return FPBitValues<is32bit, is64bit>::fromDouble(d);
const int intVal = static_cast<int>(d);
if ((intVal < minImmediateInt) | (intVal > maxImmediateInt))
return 0;
// Check for data loss from conversion to int.
if ((intVal != d) || (signbit(d) && !intVal))
return 0;
return tag(intVal << 2, NumberType);
}
ALWAYS_INLINE double JSImmediate::toDouble(const JSValue* v)
{
return FPBitValues<is32bit, is64bit>::toDouble(v);
ASSERT(isImmediate(v));
const int32_t i = static_cast<int32_t>(unTag(v)) >> 2;
if (JSImmediate::getTag(v) == UndefinedType && i)
return std::numeric_limits<double>::quiet_NaN();
return i;
}
ALWAYS_INLINE bool JSImmediate::getUInt32(const JSValue* v, uint32_t& i)
{
return FPBitValues<is32bit, is64bit>::getTruncatedUInt32(v, i);
const int32_t si = static_cast<int32_t>(unTag(v)) >> 2;
i = si;
return isNumber(v) & (si >= 0);
}
ALWAYS_INLINE bool JSImmediate::getTruncatedInt32(const JSValue* v, int32_t& i)
{
return FPBitValues<is32bit, is64bit>::getTruncatedInt32(v, i);
i = static_cast<int32_t>(unTag(v)) >> 2;
return isNumber(v);
}
ALWAYS_INLINE bool JSImmediate::getTruncatedUInt32(const JSValue* v, uint32_t& i)
{
return FPBitValues<is32bit, is64bit>::getTruncatedUInt32(v, i);
return getUInt32(v, i);
}
} // namespace KJS
......
......@@ -206,9 +206,9 @@ static NumberNode* makeNumberNode(double);
%%
Literal:
NULLTOKEN { $$ = new NullNode(); }
| TRUETOKEN { $$ = new BooleanNode(true); }
| FALSETOKEN { $$ = new BooleanNode(false); }
NULLTOKEN { $$ = new NullNode; }
| TRUETOKEN { $$ = new TrueNode; }
| FALSETOKEN { $$ = new FalseNode; }
| NUMBER { $$ = makeNumberNode($1); }
| STRING { $$ = new StringNode($1); }
| '/' /* regexp */ {
......@@ -1037,7 +1037,7 @@ static ExpressionNode* makeNegateNode(ExpressionNode* n)
static NumberNode* makeNumberNode(double d)
{
JSValue* value = JSImmediate::fromDouble(d);
JSValue* value = JSImmediate::from(d);
if (value)
return new ImmediateNumberNode(value, d);
return new NumberNode(d);
......
......@@ -655,12 +655,6 @@ void ArgumentListNode::optimizeVariableAccess(FunctionBodyNode*, DeclarationStac
nodeStack.append(expr.get());
}
JSValue *ArgumentListNode::evaluate(ExecState *)
{
ASSERT(0);
return 0; // dummy, see evaluateList()
}
// ECMA 11.2.4
void ArgumentListNode::evaluateList(ExecState* exec, List& list)
{
......@@ -679,12 +673,6 @@ void ArgumentsNode::optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks:
nodeStack.append(listNode.get());
}
JSValue *ArgumentsNode::evaluate(ExecState *)
{
ASSERT(0);
return 0; // dummy, see evaluateList()
}
// ------------------------------ NewExprNode ----------------------------------
void NewExprNode::optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack& nodeStack)
......
// -*- c-basic-offset: 2 -*-
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
......@@ -111,7 +110,7 @@ namespace KJS {
FunctionStack& functionStack;
};
class Node {
class Node : Noncopyable {
public:
Node() KJS_FAST_CALL;
Node(PlacementNewAdoptType) KJS_FAST_CALL { }
......@@ -135,9 +134,6 @@ namespace KJS {
// Used for iterative, depth-first traversal of the node tree. Does not cross function call boundaries.
virtual void optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack&) KJS_FAST_CALL { }
// Used to optimize those nodes that do extra work when returning a result, even if the result has no semantic relevance
virtual void optimizeForUnnecessaryResult() { }
protected:
Completion createErrorCompletion(ExecState *, ErrorType, const char *msg) KJS_FAST_CALL;
Completion createErrorCompletion(ExecState *, ErrorType, const char *msg, const Identifier &) KJS_FAST_CALL;
......@@ -159,10 +155,6 @@ namespace KJS {
int m_line : 31;
bool m_mayHaveDeclarations : 1;
private:
// disallow assignment
Node& operator=(const Node&) KJS_FAST_CALL;
Node(const Node &other) KJS_FAST_CALL;
};
class ExpressionNode : public Node {
......@@ -186,7 +178,10 @@ namespace KJS {
virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL = 0;
virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
};
// Used to optimize those nodes that do extra work when returning a result, even if the result has no semantic relevance
virtual void optimizeForUnnecessaryResult() { }
};
class StatementNode : public Node {
public:
......@@ -239,10 +234,10 @@ namespace KJS {
class ImmediateNumberNode : public NumberNode {
public:
ImmediateNumberNode(JSValue* v, double d) KJS_FAST_CALL : NumberNode(d), m_value(v) { ASSERT(v == JSImmediate::fromDouble(d)); }
ImmediateNumberNode(JSValue* v, double d) KJS_FAST_CALL : NumberNode(d), m_value(v) { ASSERT(v == JSImmediate::from(d)); }
virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
virtual void setValue(double d) KJS_FAST_CALL { m_double = d; m_value = JSImmediate::fromDouble(d); ASSERT(m_value); }
virtual void setValue(double d) KJS_FAST_CALL { m_double = d; m_value = JSImmediate::from(d); ASSERT(m_value); }
private:
JSValue* m_value;
};
......@@ -321,16 +316,19 @@ namespace KJS {
ALWAYS_INLINE JSValue* inlineEvaluate(ExecState*);
};
class ElementNode : public ExpressionNode {
class ElementNode : public Node {
public:
ElementNode(int e, ExpressionNode* n) KJS_FAST_CALL : elision(e), node(n) { }
ElementNode(ElementNode* l, int e, ExpressionNode* n) KJS_FAST_CALL
: elision(e), node(n) { l->next = this; }
virtual void optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
virtual void optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
PassRefPtr<ElementNode> releaseNext() KJS_FAST_CALL { return next.release(); }
virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
JSValue* evaluate(ExecState*) KJS_FAST_CALL;
private:
friend class ArrayNode;
ListRefPtr<ElementNode> next;
......@@ -355,34 +353,38 @@ namespace KJS {
bool opt;
};
class PropertyNode : public ExpressionNode {
class PropertyNode : public Node {
public:
enum Type { Constant, Getter, Setter };
PropertyNode(const Identifier& n, ExpressionNode* a, Type t) KJS_FAST_CALL
: m_name(n), assign(a), type(t) { }
virtual void optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
friend class PropertyListNode;
virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
JSValue* evaluate(ExecState*) KJS_FAST_CALL;
const Identifier& name() const { return m_name; }
private:
friend class PropertyListNode;
Identifier m_name;
RefPtr<ExpressionNode> assign;
Type type;
};
class PropertyListNode : public ExpressionNode {
class PropertyListNode : public Node {
public:
PropertyListNode(PropertyNode* n) KJS_FAST_CALL
: node(n) { }
PropertyListNode(PropertyNode* n, PropertyListNode* l) KJS_FAST_CALL
: node(n) { l->next = this; }
virtual void optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
PassRefPtr<PropertyListNode> releaseNext() KJS_FAST_CALL { return next.release(); }
virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
JSValue* evaluate(ExecState*) KJS_FAST_CALL;
PassRefPtr<PropertyListNode> releaseNext() KJS_FAST_CALL { return next.release(); }
private:
friend class ObjectLiteralNode;
RefPtr<PropertyNode> node;
......@@ -439,33 +441,35 @@ namespace KJS {
Identifier ident;
};
class ArgumentListNode : public ExpressionNode {
class ArgumentListNode : public Node {
public:
ArgumentListNode(ExpressionNode* e) KJS_FAST_CALL : expr(e) { }
ArgumentListNode(ArgumentListNode* l, ExpressionNode* e) KJS_FAST_CALL
: expr(e) { l->next = this; }
virtual void optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
void evaluateList(ExecState*, List&) KJS_FAST_CALL;
virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
PassRefPtr<ArgumentListNode> releaseNext() KJS_FAST_CALL { return next.release(); }
virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
void evaluateList(ExecState*, List&) KJS_FAST_CALL;
PassRefPtr<ArgumentListNode> releaseNext() KJS_FAST_CALL { return next.release(); }
private:
friend class ArgumentsNode;
ListRefPtr<ArgumentListNode> next;
RefPtr<ExpressionNode> expr;
};
class ArgumentsNode : public ExpressionNode {
class ArgumentsNode : public Node {
public:
ArgumentsNode() KJS_FAST_CALL { }
ArgumentsNode(ArgumentListNode* l) KJS_FAST_CALL
: listNode(l) { }
virtual void optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
void evaluateList(ExecState* exec, List& list) KJS_FAST_CALL { if (listNode) listNode->evaluateList(exec, list); }
virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
void evaluateList(ExecState* exec, List& list) KJS_FAST_CALL { if (listNode) listNode->evaluateList(exec, list); }
private:
RefPtr<ArgumentListNode> listNode;
};
......@@ -559,7 +563,7 @@ namespace KJS {
RefPtr<ArgumentsNode> args;
};
class PrePostResolveNode : public ExpressionNode {
class PrePostResolveNode : public ExpressionNode {
public:
PrePostResolveNode(const Identifier& i) KJS_FAST_CALL : m_ident(i) {}
......@@ -633,7 +637,7 @@ namespace KJS {
virtual void optimizeForUnnecessaryResult();
};
class PostfixBracketNode : public ExpressionNode {
class PostfixBracketNode : public ExpressionNode {
public:
PostfixBracketNode(ExpressionNode* b, ExpressionNode* s) KJS_FAST_CALL : m_base(b), m_subscript(s) {}
virtual void optimizeVariableAccess(FunctionBodyNode*, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
......
......@@ -200,10 +200,46 @@ inline JSValue *jsBoolean(bool b)
ALWAYS_INLINE JSValue* jsNumber(double d)
{
JSValue *v = JSImmediate::fromDouble(d);
JSValue* v = JSImmediate::from(d);
return v ? v : jsNumberCell(d);
}
ALWAYS_INLINE JSValue* jsNumber(int i)
{
JSValue* v = JSImmediate::from(i);
return v ? v : jsNumberCell(i);
}
ALWAYS_INLINE JSValue* jsNumber(unsigned i)
{
JSValue* v = JSImmediate::from(i);
return v ? v : jsNumberCell(i);
}
ALWAYS_INLINE JSValue* jsNumber(long i)
{
JSValue* v = JSImmediate::from(i);
return v ? v : jsNumberCell(i);
}
ALWAYS_INLINE JSValue* jsNumber(unsigned long i)
{
JSValue* v = JSImmediate::from(i);
return v ? v : jsNumberCell(i);
}
ALWAYS_INLINE JSValue* jsNumber(long long i)
{
JSValue* v = JSImmediate::from(i);
return v ? v : jsNumberCell(i);
}
ALWAYS_INLINE JSValue* jsNumber(unsigned long long i)
{
JSValue* v = JSImmediate::from(i);
return v ? v : jsNumberCell(i);
}
ALWAYS_INLINE JSValue* jsNumberFromAnd(ExecState *exec, JSValue* v1, JSValue* v2)
{
if (JSImmediate::areBothImmediateNumbers(v1, v2))
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment