WebKit Bugzilla
Attachment 342236 Details for
Bug 186228
: [ESNext][BigInt] Implement support for "&"
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-186228-20180608010926.patch (text/plain), 48.44 KB, created by
Caio Lima
on 2018-06-07 21:09:29 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Caio Lima
Created:
2018-06-07 21:09:29 PDT
Size:
48.44 KB
patch
obsolete
>Subversion Revision: 232610 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index ca899d934943c60faf3c24b2d2d839173b9e94c6..56926169a32bef88635b1d168c9b47855dd788d5 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,79 @@ >+2018-06-07 Caio Lima <ticaiolima@gmail.com> >+ >+ [ESNext][BigInt] Implement support for "&" >+ https://bugs.webkit.org/show_bug.cgi?id=186228 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ This patch introduces support of BigInt into bitwise "&" operation. >+ We are also introducing the ValueBitAnd DFG node, that is responsible >+ to take care of JIT for non-Int32 operands. With the introduction of this >+ new node, we renamed the BitAnd node to ArithBitAnd. The ArithBitAnd >+ follows the behavior of ArithAdd and other arithmetic nodes, where >+ the Arith<op> version always results in Number (in the case of >+ ArithBitAnd, its is always an Int32). >+ >+ Since op_bitand now can result into BigInt or Int32, we added ValueProfile >+ to this opcode. To avoid unecessary overhead, we are just profiling >+ the value when the result is a BigInt. It is safe to do in this specific >+ case, because Int32 is the only other possible outcome. >+ >+ * bytecode/CodeBlock.cpp: >+ (JSC::CodeBlock::finishCreation): >+ * bytecompiler/BytecodeGenerator.cpp: >+ (JSC::BytecodeGenerator::emitBinaryOp): >+ * dfg/DFGAbstractInterpreterInlines.h: >+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): >+ * dfg/DFGBackwardsPropagationPhase.cpp: >+ (JSC::DFG::BackwardsPropagationPhase::isWithinPowerOfTwo): >+ (JSC::DFG::BackwardsPropagationPhase::propagate): >+ * dfg/DFGByteCodeParser.cpp: >+ (JSC::DFG::ByteCodeParser::parseBlock): >+ * 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/DFGPredictionPropagationPhase.cpp: >+ * dfg/DFGSafeToExecute.h: >+ (JSC::DFG::safeToExecute): >+ * dfg/DFGSpeculativeJIT.cpp: >+ (JSC::DFG::SpeculativeJIT::compileValueBitwiseOp): >+ (JSC::DFG::SpeculativeJIT::compileBitwiseOp): >+ * dfg/DFGSpeculativeJIT.h: >+ (JSC::DFG::SpeculativeJIT::bitOp): >+ * dfg/DFGSpeculativeJIT32_64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * dfg/DFGSpeculativeJIT64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * dfg/DFGStrengthReductionPhase.cpp: >+ (JSC::DFG::StrengthReductionPhase::handleNode): >+ * ftl/FTLCapabilities.cpp: >+ (JSC::FTL::canCompile): >+ * ftl/FTLLowerDFGToB3.cpp: >+ (JSC::FTL::DFG::LowerDFGToB3::compileNode): >+ (JSC::FTL::DFG::LowerDFGToB3::compileValueBitAnd): >+ (JSC::FTL::DFG::LowerDFGToB3::compileArithBitAnd): >+ (JSC::FTL::DFG::LowerDFGToB3::compileBitAnd): Deleted. >+ * llint/LowLevelInterpreter32_64.asm: >+ * runtime/CommonSlowPaths.cpp: >+ (JSC::SLOW_PATH_DECL): >+ * runtime/JSBigInt.cpp: >+ (JSC::JSBigInt::bitwiseAnd): >+ (JSC::JSBigInt::absoluteBitwiseOp): >+ (JSC::JSBigInt::absoluteAnd): >+ (JSC::JSBigInt::absoluteOr): >+ (JSC::JSBigInt::absoluteAndNot): >+ (JSC::JSBigInt::absoluteAddOne): >+ (JSC::JSBigInt::absoluteSubOne): >+ * runtime/JSBigInt.h: >+ * runtime/JSCJSValue.h: >+ * runtime/JSCJSValueInlines.h: >+ (JSC::JSValue::toBigIntOrInt32 const): >+ > 2018-06-07 Tadeu Zagallo <tzagallo@apple.com> > > Don't try to allocate JIT memory if we don't have the JIT entitlement >diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp >index 98ef06f47a33611351c74cba411ac2f31b864a8f..46de773fe28163418a9430f8ed19ecf9e804b49d 100644 >--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp >+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp >@@ -585,6 +585,7 @@ bool CodeBlock::finishCreation(VM& vm, ScriptExecutable* ownerExecutable, Unlink > break; > } > >+ case op_bitand: > case op_to_this: { > linkValueProfile(i, opLength); > break; >diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp >index eb7da976afb118bc086c842fd6833bc4b484550d..a5033cc5ad9a31c3ade811e5de5516b856f0e27b 100644 >--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp >+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp >@@ -1736,12 +1736,22 @@ RegisterID* BytecodeGenerator::emitDec(RegisterID* srcDst) > > RegisterID* BytecodeGenerator::emitBinaryOp(OpcodeID opcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes types) > { >+ >+ if (opcodeID == op_bitand) { >+ UnlinkedValueProfile profile = emitProfiledOpcode(opcodeID); >+ instructions().append(dst->index()); >+ instructions().append(src1->index()); >+ instructions().append(src2->index()); >+ instructions().append(profile); >+ return dst; >+ } >+ > emitOpcode(opcodeID); > instructions().append(dst->index()); > instructions().append(src1->index()); > instructions().append(src2->index()); > >- if (opcodeID == op_bitor || opcodeID == op_bitand || opcodeID == op_bitxor || >+ if (opcodeID == op_bitor || opcodeID == op_bitxor || > opcodeID == op_add || opcodeID == op_mul || opcodeID == op_sub || opcodeID == op_div) > instructions().append(ArithProfile(types.first(), types.second()).bits()); > >diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >index 3ccfaf6e48335392402a3170c6e748c4e0e78fed..ce5b616d6a1f8c269f08c71303b7c8f110ee52b3 100644 >--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >@@ -373,7 +373,12 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi > break; > } > >- case BitAnd: >+ case ValueBitAnd: >+ clobberWorld(); >+ setTypeForNode(node, SpecBoolInt32 | SpecBigInt); >+ break; >+ >+ case ArithBitAnd: > case BitOr: > case BitXor: > case BitRShift: >@@ -391,7 +396,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi > int32_t a = left.asInt32(); > int32_t b = right.asInt32(); > switch (node->op()) { >- case BitAnd: >+ case ArithBitAnd: > setConstant(node, JSValue(a & b)); > break; > case BitOr: >@@ -416,7 +421,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi > break; > } > >- if (node->op() == BitAnd >+ if (node->op() == ArithBitAnd > && (isBoolInt32Speculation(forNode(node->child1()).m_type) || > isBoolInt32Speculation(forNode(node->child2()).m_type))) { > setNonCellTypeForNode(node, SpecBoolInt32); >diff --git a/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp >index 058aacf8b2a3cca0bcc955dd02ea574df6611034..13e9518df64824d3f0be604847d8b39d0b605c8d 100644 >--- a/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp >@@ -110,7 +110,7 @@ private: > return isWithinPowerOfTwoForConstant<power>(node); > } > >- case BitAnd: { >+ case ArithBitAnd: { > if (power > 31) > return true; > >@@ -207,7 +207,7 @@ private: > case CheckVarargs: > break; > >- case BitAnd: >+ case ArithBitAnd: > case BitOr: > case BitXor: > case BitRShift: >diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >index e98dfe58995e684f5192517b48f2d1f5c5d73b1c..c26b00b7c1359c6050dd5ec72011bdcc915ae4fe 100644 >--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >@@ -4634,7 +4634,11 @@ void ByteCodeParser::parseBlock(unsigned limit) > case op_bitand: { > Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); > Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); >- set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(BitAnd, op1, op2)); >+ if (getPredictionWithoutOSRExit() != SpecBigInt) >+ set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(ArithBitAnd, op1, op2)); >+ else >+ set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(ValueBitAnd, op1, op2)); >+ > NEXT_OPCODE(op_bitand); > } > >diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h >index 6c58663463e2198f31a3233ba814c9cc4763d23b..db302f9cc740596e8c18ff062bb657c5c458417c 100644 >--- a/Source/JavaScriptCore/dfg/DFGClobberize.h >+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h >@@ -262,7 +262,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu > def(PureValue(node, node->queriedType())); > return; > >- case BitAnd: >+ case ArithBitAnd: > case BitOr: > case BitXor: > case BitLShift: >@@ -634,6 +634,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu > case InByVal: > case InById: > case HasOwnProperty: >+ case ValueBitAnd: > case ValueNegate: > case ValueAdd: > case SetFunctionName: >diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >index d2333daae685caaa8604916495b456f72ed6eeec..06a1814bb5d5290b000d43811fc2001a24224c99 100644 >--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >@@ -67,7 +67,7 @@ bool doesGC(Graph& graph, Node* node) > case Flush: > case PhantomLocal: > case SetArgument: >- case BitAnd: >+ case ArithBitAnd: > case BitOr: > case BitXor: > case BitLShift: >@@ -96,6 +96,7 @@ bool doesGC(Graph& graph, Node* node) > case ArithTrunc: > case ArithFRound: > case ArithUnary: >+ case ValueBitAnd: > case ValueAdd: > case ValueNegate: > case TryGetById: >diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >index 9d6ef7a18833a8e31f5fd69e86f2e9fbe4b98663..e924b6ce9f93399dd7e71ddb522f0ac4c8ddd507 100644 >--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >@@ -99,7 +99,24 @@ private: > return; > } > >- case BitAnd: >+ case ValueBitAnd: >+ fixEdge<UntypedUse>(node->child1()); >+ fixEdge<UntypedUse>(node->child2()); >+ break; >+ >+ case ArithBitAnd: { >+ if (Node::shouldSpeculateUntypedForBitOps(node->child1().node(), node->child2().node())) { >+ fixEdge<UntypedUse>(node->child1()); >+ fixEdge<UntypedUse>(node->child2()); >+ node->setOp(ValueBitAnd); >+ node->setResult(NodeResultJS); >+ break; >+ } >+ fixIntConvertingEdge(node->child1()); >+ fixIntConvertingEdge(node->child2()); >+ break; >+ } >+ > case BitOr: > case BitXor: > case BitRShift: >diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h >index a50e5208c9621e157905283cb2556d173124719d..50f44e50123da1ae8606214d882c8f4c20938031 100644 >--- a/Source/JavaScriptCore/dfg/DFGNodeType.h >+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h >@@ -111,7 +111,8 @@ namespace JSC { namespace DFG { > macro(InvalidationPoint, NodeMustGenerate) \ > \ > /* Nodes for bitwise operations. */\ >- macro(BitAnd, NodeResultInt32) \ >+ macro(ValueBitAnd, NodeResultJS | NodeMustGenerate) \ >+ macro(ArithBitAnd, NodeResultInt32) \ > macro(BitOr, NodeResultInt32) \ > macro(BitXor, NodeResultInt32) \ > macro(BitLShift, NodeResultInt32) \ >diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp >index 7c9e70b6bd78b9993fd6dd4ae1e00614dd2a61ae..08ee7b23ea21c6917704f67312fb3dcf23ce4b95 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp >+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp >@@ -346,11 +346,22 @@ EncodedJSValue JIT_OPERATION operationValueBitAnd(ExecState* exec, EncodedJSValu > JSValue op1 = JSValue::decode(encodedOp1); > JSValue op2 = JSValue::decode(encodedOp2); > >- int32_t a = op1.toInt32(exec); >+ auto leftNumeric = op1.toBigIntOrInt32(exec); > RETURN_IF_EXCEPTION(scope, encodedJSValue()); >- scope.release(); >- int32_t b = op2.toInt32(exec); >- return JSValue::encode(jsNumber(a & b)); >+ auto rightNumeric = op2.toBigIntOrInt32(exec); >+ RETURN_IF_EXCEPTION(scope, encodedJSValue()); >+ >+ if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) { >+ if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) { >+ JSBigInt* result = JSBigInt::bitwiseAnd(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)); >+ RETURN_IF_EXCEPTION(scope, encodedJSValue()); >+ return JSValue::encode(result); >+ } >+ >+ return throwVMTypeError(exec, scope, "Invalid mix of BigInt and other type in bitwise and operation."); >+ } >+ >+ return JSValue::encode(jsNumber(WTF::get<int32_t>(leftNumeric) & WTF::get<int32_t>(rightNumeric))); > } > > EncodedJSValue JIT_OPERATION operationValueBitOr(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) >@@ -470,7 +481,7 @@ EncodedJSValue JIT_OPERATION operationValueDiv(ExecState* exec, EncodedJSValue e > return JSValue::encode(result); > } > >- return throwVMTypeError(exec, scope, "Invalid operand in BigInt operation."); >+ return throwVMTypeError(exec, scope, "Invalid mix of BigInt and other type in division operation."); > } > > scope.release(); >diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >index e0dd115b7e7301de4ed537c95fc7fdfae7ab662d..ebaaa19cb76be95ccd84bc3e7418ba688bb08956 100644 >--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >@@ -692,7 +692,12 @@ private: > setPrediction(type); > break; > } >- case BitAnd: >+ >+ case ValueBitAnd: >+ setPrediction(SpecBigInt); >+ break; >+ >+ case ArithBitAnd: > case BitOr: > case BitXor: > case BitRShift: >diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >index 267c8a1a5134ab8aae8315f165fe5f614820c359..2a8c462ea990bf769cd063ec264300600284e612 100644 >--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >@@ -191,7 +191,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno > case Flush: > case PhantomLocal: > case SetArgument: >- case BitAnd: >+ case ArithBitAnd: > case BitOr: > case BitXor: > case BitLShift: >@@ -220,6 +220,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno > case ArithCeil: > case ArithTrunc: > case ArithUnary: >+ case ValueBitAnd: > case ValueNegate: > case ValueAdd: > case TryGetById: >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >index b04bde2f0712b5badf15208e4278e74ad30c9600..23612454f39686fb0da8c252af3a7f611259b3e0 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >@@ -3589,6 +3589,19 @@ void SpeculativeJIT::emitUntypedBitOp(Node* node) > jsValueResult(resultRegs, node); > } > >+void SpeculativeJIT::compileValueBitwiseOp(Node* node) >+{ >+ NodeType op = node->op(); >+ >+ switch (op) { >+ case ValueBitAnd: >+ emitUntypedBitOp<JITBitAndGenerator, operationValueBitAnd>(node); >+ return; >+ default: >+ RELEASE_ASSERT_NOT_REACHED(); >+ } >+} >+ > void SpeculativeJIT::compileBitwiseOp(Node* node) > { > NodeType op = node->op(); >@@ -3597,9 +3610,6 @@ void SpeculativeJIT::compileBitwiseOp(Node* node) > > if (leftChild.useKind() == UntypedUse || rightChild.useKind() == UntypedUse) { > switch (op) { >- case BitAnd: >- emitUntypedBitOp<JITBitAndGenerator, operationValueBitAnd>(node); >- return; > case BitOr: > emitUntypedBitOp<JITBitOrGenerator, operationValueBitOr>(node); > return; >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >index ae7fe8b92981d49e42aec5b2eb12f3bb172c117f..79cc2d691c994c405fe48d7a99709772636838ae 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >@@ -633,7 +633,7 @@ public: > void bitOp(NodeType op, int32_t imm, GPRReg op1, GPRReg result) > { > switch (op) { >- case BitAnd: >+ case ArithBitAnd: > m_jit.and32(Imm32(imm), op1, result); > break; > case BitOr: >@@ -649,7 +649,7 @@ public: > void bitOp(NodeType op, GPRReg op1, GPRReg op2, GPRReg result) > { > switch (op) { >- case BitAnd: >+ case ArithBitAnd: > m_jit.and32(op1, op2, result); > break; > case BitOr: >@@ -1332,6 +1332,7 @@ public: > template<typename SnippetGenerator, J_JITOperation_EJJ slowPathFunction> > void emitUntypedBitOp(Node*); > void compileBitwiseOp(Node*); >+ void compileValueBitwiseOp(Node*); > > void emitUntypedRightShiftBitOp(Node*); > void compileShiftOp(Node*); >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >index 2dc247ea01026492e3772b81a11d1b8092b6452b..c5547aaa384b6b7c71f2f2ed18e31ec37af16522 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >@@ -1978,7 +1978,11 @@ void SpeculativeJIT::compile(Node* node) > recordSetLocal(dataFormatFor(node->variableAccessData()->flushFormat())); > break; > >- case BitAnd: >+ case ValueBitAnd: >+ compileValueBitwiseOp(node); >+ break; >+ >+ case ArithBitAnd: > case BitOr: > case BitXor: > compileBitwiseOp(node); >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >index b82370f76f019c7bb273dd1bdebef49856362b5c..43eb38778a0502375287c2ceafdd0f094f036cfb 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >@@ -2080,7 +2080,11 @@ void SpeculativeJIT::compile(Node* node) > recordSetLocal(dataFormatFor(node->variableAccessData()->flushFormat())); > break; > >- case BitAnd: >+ case ValueBitAnd: >+ compileValueBitwiseOp(node); >+ break; >+ >+ case ArithBitAnd: > case BitOr: > case BitXor: > compileBitwiseOp(node); >diff --git a/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp b/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp >index 2e98b82d84e2f07042b2f13fae705881516b5e92..4fb4123c540b9aa77bea47b7a056d53159e06428 100644 >--- a/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp >@@ -88,7 +88,7 @@ private: > break; > > case BitXor: >- case BitAnd: >+ case ArithBitAnd: > handleCommutativity(); > break; > >diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >index fcef95389685851d8853a1fc1bdab14e9588e141..0d48bc110a4691b2c04c595b79750acc64df9bce 100644 >--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >@@ -58,7 +58,7 @@ inline CapabilityLevel canCompile(Node* node) > case PhantomLocal: > case SetArgument: > case Return: >- case BitAnd: >+ case ArithBitAnd: > case BitOr: > case BitXor: > case BitRShift: >@@ -86,6 +86,7 @@ inline CapabilityLevel canCompile(Node* node) > case GetGlobalVar: > case GetGlobalLexicalVariable: > case PutGlobalVariable: >+ case ValueBitAnd: > case ValueNegate: > case ValueAdd: > case StrCat: >diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >index de31efb5fc1067a7a327d816dd358c31add0fc81..5cd4dbd5d08ba47038f0ad147fb117403497406e 100644 >--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >@@ -649,8 +649,11 @@ private: > case ArithUnary: > compileArithUnary(); > break; >- case DFG::BitAnd: >- compileBitAnd(); >+ case ValueBitAnd: >+ compileValueBitAnd(); >+ break; >+ case DFG::ArithBitAnd: >+ compileArithBitAnd(); > break; > case DFG::BitOr: > compileBitOr(); >@@ -2790,12 +2793,14 @@ private: > } > } > >- void compileBitAnd() >+ void compileValueBitAnd() >+ { >+ emitBinaryBitOpSnippet<JITBitAndGenerator>(operationValueBitAnd); >+ return; >+ } >+ >+ void compileArithBitAnd() > { >- if (m_node->isBinaryUseKind(UntypedUse)) { >- emitBinaryBitOpSnippet<JITBitAndGenerator>(operationValueBitAnd); >- return; >- } > setInt32(m_out.bitAnd(lowInt32(m_node->child1()), lowInt32(m_node->child2()))); > } > >diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >index 1dafc63caff78ebafa37f06a2b5d6748dde3fee3..75980b3c6816e407e66fcd863b20308e3ed54a06 100644 >--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >@@ -646,11 +646,21 @@ SLOW_PATH_DECL(slow_path_unsigned) > SLOW_PATH_DECL(slow_path_bitand) > { > BEGIN(); >- int32_t a = OP_C(2).jsValue().toInt32(exec); >- if (UNLIKELY(throwScope.exception())) >- RETURN(JSValue()); >- int32_t b = OP_C(3).jsValue().toInt32(exec); >- RETURN(jsNumber(a & b)); >+ auto leftNumeric = OP_C(2).jsValue().toBigIntOrInt32(exec); >+ CHECK_EXCEPTION(); >+ auto rightNumeric = OP_C(3).jsValue().toBigIntOrInt32(exec); >+ CHECK_EXCEPTION(); >+ if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) { >+ if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) { >+ JSBigInt* result = JSBigInt::bitwiseAnd(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)); >+ CHECK_EXCEPTION(); >+ RETURN_PROFILED(op_bitand, result); >+ } >+ >+ THROW(createTypeError(exec, "Invalid mix of BigInt and other type in bitwise and operation.")); >+ } >+ >+ RETURN(jsNumber(WTF::get<int32_t>(leftNumeric) & WTF::get<int32_t>(rightNumeric))); > } > > SLOW_PATH_DECL(slow_path_bitor) >diff --git a/Source/JavaScriptCore/runtime/JSBigInt.cpp b/Source/JavaScriptCore/runtime/JSBigInt.cpp >index 0fde648ea4877c1f3692e86fa8b4f1306f74686c..7e560bb67e8363e7497d5fa8728afdc50e9eeac3 100644 >--- a/Source/JavaScriptCore/runtime/JSBigInt.cpp >+++ b/Source/JavaScriptCore/runtime/JSBigInt.cpp >@@ -381,6 +381,32 @@ JSBigInt* JSBigInt::sub(VM& vm, JSBigInt* x, JSBigInt* y) > return absoluteSub(vm, y, x, !xSign); > } > >+JSBigInt* JSBigInt::bitwiseAnd(ExecState* exec, JSBigInt* x, JSBigInt* y) >+{ >+ VM& vm = exec->vm(); >+ if (!x->sign() && !y->sign()) >+ return absoluteAnd(exec, x, y); >+ >+ if (x->sign() && y->sign()) { >+ int resultLength = std::max(x->length(), y->length()) + 1; >+ // (-x) & (-y) == ~(x-1) & ~(y-1) == ~((x-1) | (y-1)) >+ // == -(((x-1) | (y-1)) + 1) >+ JSBigInt* result = absoluteSubOne(vm, x, resultLength); >+ JSBigInt* y1 = absoluteSubOne(vm, y, y->length()); >+ result = absoluteOr(exec, result, y1); >+ >+ return absoluteAddOne(vm, result, true); >+ } >+ >+ ASSERT(x->sign() != y->sign()); >+ // Assume that x is the positive BigInt. >+ if (x->sign()) >+ std::swap(x, y); >+ >+ // x & (-y) == x & ~(y-1) == x & ~(y-1) >+ return absoluteAndNot(exec, x, absoluteSubOne(vm, y, y->length())); >+} >+ > #if USE(JSVALUE32_64) > #define HAVE_TWO_DIGIT 1 > typedef uint64_t TwoDigit; >@@ -993,6 +1019,130 @@ JSBigInt* JSBigInt::absoluteLeftShiftAlwaysCopy(VM& vm, JSBigInt* x, unsigned sh > return result; > } > >+// Helper for Absolute{And,AndNot,Or,Xor}. >+// Performs the given binary {op} on digit pairs of {x} and {y}; when the >+// end of the shorter of the two is reached, {extraDigits} configures how >+// remaining digits in the longer input (if {symmetric} == Symmetric, in >+// {x} otherwise) are handled: copied to the result or ignored. >+// Example: >+// y: [ y2 ][ y1 ][ y0 ] >+// x: [ x3 ][ x2 ][ x1 ][ x0 ] >+// | | | | >+// (Copy) (op) (op) (op) >+// | | | | >+// v v v v >+// result: [ 0 ][ x3 ][ r2 ][ r1 ][ r0 ] >+inline JSBigInt* JSBigInt::absoluteBitwiseOp(ExecState* exec, JSBigInt* x, JSBigInt* y, ExtraDigitsHandling extraDigits, SymmetricOp symmetric, std::function<Digit(Digit, Digit)> op) >+{ >+ VM& vm = exec->vm(); >+ >+ unsigned xLength = x->length(); >+ unsigned yLength = y->length(); >+ unsigned numPairs = yLength; >+ if (xLength < yLength) { >+ numPairs = xLength; >+ if (symmetric == SymmetricOp::Symmetric) { >+ std::swap(x, y); >+ std::swap(xLength, yLength); >+ } >+ } >+ >+ ASSERT(numPairs == std::min(xLength, yLength)); >+ unsigned resultLength = extraDigits == ExtraDigitsHandling::Copy ? xLength : numPairs; >+ JSBigInt* result = createWithLength(vm, resultLength); >+ >+ unsigned i = 0; >+ for (; i < numPairs; i++) >+ result->setDigit(i, op(x->digit(i), y->digit(i))); >+ >+ if (extraDigits == ExtraDigitsHandling::Copy) { >+ for (; i < xLength; i++) >+ result->setDigit(i, x->digit(i)); >+ } >+ >+ for (; i < resultLength; i++) >+ result->setDigit(i, 0); >+ >+ return result->rightTrim(vm); >+} >+ >+JSBigInt* JSBigInt::absoluteAnd(ExecState* exec, JSBigInt* x, JSBigInt* y) >+{ >+ auto digitOperation = [](Digit a, Digit b) { >+ return a & b; >+ }; >+ return absoluteBitwiseOp(exec, x, y, ExtraDigitsHandling::Skip, SymmetricOp::Symmetric, digitOperation); >+} >+ >+JSBigInt* JSBigInt::absoluteOr(ExecState* exec, JSBigInt* x, JSBigInt* y) >+{ >+ auto digitOperation = [](Digit a, Digit b) { >+ return a | b; >+ }; >+ return absoluteBitwiseOp(exec, x, y, ExtraDigitsHandling::Copy, SymmetricOp::Symmetric, digitOperation); >+} >+ >+JSBigInt* JSBigInt::absoluteAndNot(ExecState* exec, JSBigInt* x, JSBigInt* y) >+{ >+ auto digitOperation = [](Digit a, Digit b) { >+ return a & ~b; >+ }; >+ return absoluteBitwiseOp(exec, x, y, ExtraDigitsHandling::Copy, SymmetricOp::NotSymmetric, digitOperation); >+} >+ >+JSBigInt* JSBigInt::absoluteAddOne(VM& vm, JSBigInt* x, bool sign) >+{ >+ unsigned inputLength = x->length(); >+ // The addition will overflow into a new digit if all existing digits are >+ // at maximum. >+ bool willOverflow = true; >+ for (unsigned i = 0; i < inputLength; i++) { >+ if (std::numeric_limits<Digit>::max() != x->digit(i)) { >+ willOverflow = false; >+ break; >+ } >+ } >+ >+ unsigned resultLength = inputLength + willOverflow; >+ JSBigInt* result = createWithLength(vm, resultLength); >+ >+ Digit carry = 1; >+ for (unsigned i = 0; i < inputLength; i++) { >+ Digit newCarry = 0; >+ result->setDigit(i, digitAdd(x->digit(i), carry, newCarry)); >+ carry = newCarry; >+ } >+ if (resultLength > inputLength) >+ result->setDigit(inputLength, carry); >+ else >+ ASSERT(!carry); >+ >+ result->setSign(sign); >+ return result->rightTrim(vm); >+} >+ >+// Like the above, but you can specify that the allocated result should have >+// length {resultLength}, which must be at least as large as {x->length()}. >+JSBigInt* JSBigInt::absoluteSubOne(VM& vm, JSBigInt* x, unsigned resultLength) >+{ >+ ASSERT(!x->isZero()); >+ ASSERT(resultLength >= x->length()); >+ JSBigInt* result = createWithLength(vm, resultLength); >+ >+ unsigned length = x->length(); >+ Digit borrow = 1; >+ for (unsigned i = 0; i < length; i++) { >+ Digit newBorrow = 0; >+ result->setDigit(i, digitSub(x->digit(i), borrow, newBorrow)); >+ borrow = newBorrow; >+ } >+ ASSERT(!borrow); >+ for (unsigned i = length; i < resultLength; i++) >+ result->setDigit(i, borrow); >+ >+ return result->rightTrim(vm); >+} >+ > // Lookup table for the maximum number of bits required per character of a > // base-N string representation of a number. To increase accuracy, the array > // value is the actual value multiplied by 32. To generate this table: >diff --git a/Source/JavaScriptCore/runtime/JSBigInt.h b/Source/JavaScriptCore/runtime/JSBigInt.h >index 4af7a5f7f24366c37450c9642e412605b06043d5..07fe4443b63e91bf9865b3c0df18ebb456a9ea50 100644 >--- a/Source/JavaScriptCore/runtime/JSBigInt.h >+++ b/Source/JavaScriptCore/runtime/JSBigInt.h >@@ -112,7 +112,9 @@ public: > static JSBigInt* divide(ExecState*, JSBigInt* x, JSBigInt* y); > static JSBigInt* remainder(ExecState*, JSBigInt* x, JSBigInt* y); > static JSBigInt* unaryMinus(VM&, JSBigInt* x); >- >+ >+ static JSBigInt* bitwiseAnd(ExecState*, JSBigInt* x, JSBigInt* y); >+ > private: > > using Digit = uintptr_t; >@@ -148,6 +150,24 @@ private: > Digit absoluteInplaceSub(JSBigInt* subtrahend, unsigned startIndex); > void inplaceRightShift(unsigned shift); > >+ enum class ExtraDigitsHandling { >+ Copy, >+ Skip >+ }; >+ >+ enum class SymmetricOp { >+ Symmetric, >+ NotSymmetric >+ }; >+ >+ static JSBigInt* absoluteBitwiseOp(ExecState*, JSBigInt* x, JSBigInt* y, ExtraDigitsHandling, SymmetricOp, std::function<Digit(Digit, Digit)> op); >+ static JSBigInt* absoluteAnd(ExecState*, JSBigInt* x, JSBigInt* y); >+ static JSBigInt* absoluteOr(ExecState*, JSBigInt* x, JSBigInt* y); >+ static JSBigInt* absoluteAndNot(ExecState*, JSBigInt* x, JSBigInt* y); >+ >+ static JSBigInt* absoluteAddOne(VM&, JSBigInt* x, bool sign); >+ static JSBigInt* absoluteSubOne(VM&, JSBigInt* x, unsigned resultLength); >+ > // Digit arithmetic helpers. > static Digit digitAdd(Digit a, Digit b, Digit& carry); > static Digit digitSub(Digit a, Digit b, Digit& borrow); >diff --git a/Source/JavaScriptCore/runtime/JSCJSValue.h b/Source/JavaScriptCore/runtime/JSCJSValue.h >index 94d5a515e96c9f21aed82bb0bec9e6da69662af3..af0fcb0d9797f9316825a8c711594811e307b69d 100644 >--- a/Source/JavaScriptCore/runtime/JSCJSValue.h >+++ b/Source/JavaScriptCore/runtime/JSCJSValue.h >@@ -259,6 +259,7 @@ public: > double toNumber(ExecState*) const; > > Variant<JSBigInt*, double> toNumeric(ExecState*) const; >+ Variant<JSBigInt*, int32_t> toBigIntOrInt32(ExecState*) const; > > // toNumber conversion if it can be done without side effects. > std::optional<double> toNumberFromPrimitive() const; >diff --git a/Source/JavaScriptCore/runtime/JSCJSValueInlines.h b/Source/JavaScriptCore/runtime/JSCJSValueInlines.h >index 4ba9d507deb5fb5c566ee675b2cf11b10df49c11..3edbfd9d49a6cd4bcd168db489df8b134661c07a 100644 >--- a/Source/JavaScriptCore/runtime/JSCJSValueInlines.h >+++ b/Source/JavaScriptCore/runtime/JSCJSValueInlines.h >@@ -750,6 +750,24 @@ ALWAYS_INLINE Variant<JSBigInt*, double> JSValue::toNumeric(ExecState* exec) con > return value; > } > >+ALWAYS_INLINE Variant<JSBigInt*, int32_t> JSValue::toBigIntOrInt32(ExecState* exec) const >+{ >+ if (isInt32()) >+ return asInt32(); >+ if (isBigInt()) >+ return asBigInt(*this); >+ >+ VM& vm = exec->vm(); >+ auto scope = DECLARE_THROW_SCOPE(vm); >+ JSValue primValue = this->toPrimitive(exec, PreferNumber); >+ RETURN_IF_EXCEPTION(scope, 0); >+ if (primValue.isBigInt()) >+ return asBigInt(primValue); >+ int32_t value = primValue.toInt32(exec); >+ RETURN_IF_EXCEPTION(scope, 0); >+ return value; >+} >+ > inline JSObject* JSValue::toObject(ExecState* exec) const > { > return isCell() ? asCell()->toObject(exec, exec->lexicalGlobalObject()) : toObjectSlowCase(exec, exec->lexicalGlobalObject()); >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index 9f29e82dcb51487eb9b11212171363de8fee13b0..cf845663e345c5c36694e9dae2e7fa24ddb5ae3e 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,12 @@ >+2018-06-07 Caio Lima <ticaiolima@gmail.com> >+ >+ [ESNext][BigInt] Implement support for "&" >+ https://bugs.webkit.org/show_bug.cgi?id=186228 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * Scripts/run-jsc: >+ > 2018-06-07 Fujii Hironori <Hironori.Fujii@sony.com> > > [Win][MiniBrowser] MiniBrowser::updateDeviceScaleFactor should be a MainWindow's method >diff --git a/Tools/Scripts/run-jsc b/Tools/Scripts/run-jsc >index 26374bc7c86824c2e226b78edf1c18497391445f..ddb244e302db442dd5f2fbf66257e6299a641725 100755 >--- a/Tools/Scripts/run-jsc >+++ b/Tools/Scripts/run-jsc >@@ -50,9 +50,9 @@ setConfiguration(); > my $jsc; > if ($debugger) { > my $debuggerCmd = defined($ENV{"DEBUGGER"}) ? $ENV{"DEBUGGER"} : "lldb"; >- $jsc = $debuggerCmd . " " . File::Spec->catfile(jscProductDir(), "jsc -- --useDollarVM=1") . "@ARGV"; >+ $jsc = $debuggerCmd . " " . File::Spec->catfile(jscProductDir(), "jsc -- --useDollarVM=1 ") . "@ARGV"; > } else { >- $jsc = File::Spec->catfile(jscProductDir(), "jsc --useDollarVM=1") . "@ARGV"; >+ $jsc = File::Spec->catfile(jscProductDir(), "jsc --useDollarVM=1 ") . "@ARGV"; > } > > my $dyld = jscProductDir(); >diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog >index 64119c9eaf9c0a8ffa0a4073c802b1c8e71ad37e..d53d380cca185222eafecc9fb9a49ab7ac0e3ec1 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,17 @@ >+2018-06-07 Caio Lima <ticaiolima@gmail.com> >+ >+ [ESNext][BigInt] Implement support for "&" >+ https://bugs.webkit.org/show_bug.cgi?id=186228 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * stress/big-int-bitwise-and-general.js: Added. >+ * stress/big-int-bitwise-and-jit.js: Added. >+ * stress/big-int-bitwise-and-memory-stress.js: Added. >+ * stress/big-int-bitwise-and-to-primitive-precedence.js: Added. >+ * stress/big-int-bitwise-and-type-error.js: Added. >+ * stress/big-int-bitwise-and-wrapped-value.js: Added. >+ > 2018-06-07 Saam Barati <sbarati@apple.com> > > Make DFG to FTL OSR entry code more sane by removing bad RELEASE_ASSERTS and making it trigger compiles in outer loops before inner ones >diff --git a/JSTests/stress/big-int-bitwise-and-general.js b/JSTests/stress/big-int-bitwise-and-general.js >new file mode 100644 >index 0000000000000000000000000000000000000000..56e798e5006dbebc86d979fdbfdfbbbf817d479a >--- /dev/null >+++ b/JSTests/stress/big-int-bitwise-and-general.js >@@ -0,0 +1,97 @@ >+//@ runBigIntEnabled >+ >+// Copyright (C) 2017 Josh Wolfe. All rights reserved. >+// This code is governed by the BSD license found in the LICENSE file. >+ >+function assert(a) { >+ if (!a) >+ throw new Error("Bad assertion"); >+} >+ >+assert.sameValue = function (input, expected, message) { >+ if (input !== expected) >+ throw new Error(message); >+} >+ >+assert.sameValue(0b00n & 0b00n, 0b00n, "0b00n & 0b00n === 0b00n"); >+assert.sameValue(0b00n & 0b01n, 0b00n, "0b00n & 0b01n === 0b00n"); >+assert.sameValue(0b01n & 0b00n, 0b00n, "0b01n & 0b00n === 0b00n"); >+assert.sameValue(0b00n & 0b10n, 0b00n, "0b00n & 0b10n === 0b00n"); >+assert.sameValue(0b10n & 0b00n, 0b00n, "0b10n & 0b00n === 0b00n"); >+assert.sameValue(0b00n & 0b11n, 0b00n, "0b00n & 0b11n === 0b00n"); >+assert.sameValue(0b11n & 0b00n, 0b00n, "0b11n & 0b00n === 0b00n"); >+assert.sameValue(0b01n & 0b01n, 0b01n, "0b01n & 0b01n === 0b01n"); >+assert.sameValue(0b01n & 0b10n, 0b00n, "0b01n & 0b10n === 0b00n"); >+assert.sameValue(0b10n & 0b01n, 0b00n, "0b10n & 0b01n === 0b00n"); >+assert.sameValue(0b01n & 0b11n, 0b01n, "0b01n & 0b11n === 0b01n"); >+assert.sameValue(0b11n & 0b01n, 0b01n, "0b11n & 0b01n === 0b01n"); >+assert.sameValue(0b10n & 0b10n, 0b10n, "0b10n & 0b10n === 0b10n"); >+assert.sameValue(0b10n & 0b11n, 0b10n, "0b10n & 0b11n === 0b10n"); >+assert.sameValue(0b11n & 0b10n, 0b10n, "0b11n & 0b10n === 0b10n"); >+assert.sameValue(0xffffffffn & 0n, 0n, "0xffffffffn & 0n === 0n"); >+assert.sameValue(0n & 0xffffffffn, 0n, "0n & 0xffffffffn === 0n"); >+assert.sameValue(0xffffffffn & 0xffffffffn, 0xffffffffn, "0xffffffffn & 0xffffffffn === 0xffffffffn"); >+assert.sameValue(0xffffffffffffffffn & 0n, 0n, "0xffffffffffffffffn & 0n === 0n"); >+assert.sameValue(0n & 0xffffffffffffffffn, 0n, "0n & 0xffffffffffffffffn === 0n"); >+assert.sameValue(0xffffffffffffffffn & 0xffffffffn, 0xffffffffn, "0xffffffffffffffffn & 0xffffffffn === 0xffffffffn"); >+assert.sameValue(0xffffffffn & 0xffffffffffffffffn, 0xffffffffn, "0xffffffffn & 0xffffffffffffffffn === 0xffffffffn"); >+assert.sameValue( >+ 0xffffffffffffffffn & 0xffffffffffffffffn, 0xffffffffffffffffn, >+ "0xffffffffffffffffn & 0xffffffffffffffffn === 0xffffffffffffffffn"); >+assert.sameValue( >+ 0xbf2ed51ff75d380fd3be813ec6185780n & 0x4aabef2324cedff5387f1f65n, 0x42092803008e813400181700n, >+ "0xbf2ed51ff75d380fd3be813ec6185780n & 0x4aabef2324cedff5387f1f65n === 0x42092803008e813400181700n"); >+assert.sameValue( >+ 0x4aabef2324cedff5387f1f65n & 0xbf2ed51ff75d380fd3be813ec6185780n, 0x42092803008e813400181700n, >+ "0x4aabef2324cedff5387f1f65n & 0xbf2ed51ff75d380fd3be813ec6185780n === 0x42092803008e813400181700n"); >+assert.sameValue(0n & -1n, 0n, "0n & -1n === 0n"); >+assert.sameValue(-1n & 0n, 0n, "-1n & 0n === 0n"); >+assert.sameValue(0n & -2n, 0n, "0n & -2n === 0n"); >+assert.sameValue(-2n & 0n, 0n, "-2n & 0n === 0n"); >+assert.sameValue(1n & -2n, 0n, "1n & -2n === 0n"); >+assert.sameValue(-2n & 1n, 0n, "-2n & 1n === 0n"); >+assert.sameValue(2n & -2n, 2n, "2n & -2n === 2n"); >+assert.sameValue(-2n & 2n, 2n, "-2n & 2n === 2n"); >+assert.sameValue(2n & -3n, 0n, "2n & -3n === 0n"); >+assert.sameValue(-3n & 2n, 0n, "-3n & 2n === 0n"); >+assert.sameValue(-1n & -2n, -2n, "-1n & -2n === -2n"); >+assert.sameValue(-2n & -1n, -2n, "-2n & -1n === -2n"); >+assert.sameValue(-2n & -2n, -2n, "-2n & -2n === -2n"); >+assert.sameValue(-2n & -3n, -4n, "-2n & -3n === -4n"); >+assert.sameValue(-3n & -2n, -4n, "-3n & -2n === -4n"); >+assert.sameValue(0xffffffffn & -1n, 0xffffffffn, "0xffffffffn & -1n === 0xffffffffn"); >+assert.sameValue(-1n & 0xffffffffn, 0xffffffffn, "-1n & 0xffffffffn === 0xffffffffn"); >+assert.sameValue(0xffffffffffffffffn & -1n, 0xffffffffffffffffn, "0xffffffffffffffffn & -1n === 0xffffffffffffffffn"); >+assert.sameValue(-1n & 0xffffffffffffffffn, 0xffffffffffffffffn, "-1n & 0xffffffffffffffffn === 0xffffffffffffffffn"); >+assert.sameValue( >+ 0xbf2ed51ff75d380fd3be813ec6185780n & -0x4aabef2324cedff5387f1f65n, 0xbf2ed51fb554100cd330000ac6004080n, >+ "0xbf2ed51ff75d380fd3be813ec6185780n & -0x4aabef2324cedff5387f1f65n === 0xbf2ed51fb554100cd330000ac6004080n"); >+assert.sameValue( >+ -0x4aabef2324cedff5387f1f65n & 0xbf2ed51ff75d380fd3be813ec6185780n, 0xbf2ed51fb554100cd330000ac6004080n, >+ "-0x4aabef2324cedff5387f1f65n & 0xbf2ed51ff75d380fd3be813ec6185780n === 0xbf2ed51fb554100cd330000ac6004080n"); >+assert.sameValue( >+ -0xbf2ed51ff75d380fd3be813ec6185780n & 0x4aabef2324cedff5387f1f65n, 0x8a2c72024405ec138670800n, >+ "-0xbf2ed51ff75d380fd3be813ec6185780n & 0x4aabef2324cedff5387f1f65n === 0x8a2c72024405ec138670800n"); >+assert.sameValue( >+ 0x4aabef2324cedff5387f1f65n & -0xbf2ed51ff75d380fd3be813ec6185780n, 0x8a2c72024405ec138670800n, >+ "0x4aabef2324cedff5387f1f65n & -0xbf2ed51ff75d380fd3be813ec6185780n === 0x8a2c72024405ec138670800n"); >+assert.sameValue( >+ -0xbf2ed51ff75d380fd3be813ec6185780n & -0x4aabef2324cedff5387f1f65n, -0xbf2ed51fffffff2ff7fedffffe7f5f80n, >+ "-0xbf2ed51ff75d380fd3be813ec6185780n & -0x4aabef2324cedff5387f1f65n === -0xbf2ed51fffffff2ff7fedffffe7f5f80n"); >+assert.sameValue( >+ -0x4aabef2324cedff5387f1f65n & -0xbf2ed51ff75d380fd3be813ec6185780n, -0xbf2ed51fffffff2ff7fedffffe7f5f80n, >+ "-0x4aabef2324cedff5387f1f65n & -0xbf2ed51ff75d380fd3be813ec6185780n === -0xbf2ed51fffffff2ff7fedffffe7f5f80n"); >+assert.sameValue(-0xffffffffn & 0n, 0n, "-0xffffffffn & 0n === 0n"); >+assert.sameValue(0n & -0xffffffffn, 0n, "0n & -0xffffffffn === 0n"); >+assert.sameValue( >+ -0xffffffffffffffffn & 0x10000000000000000n, 0x10000000000000000n, >+ "-0xffffffffffffffffn & 0x10000000000000000n === 0x10000000000000000n"); >+assert.sameValue( >+ 0x10000000000000000n & -0xffffffffffffffffn, 0x10000000000000000n, >+ "0x10000000000000000n & -0xffffffffffffffffn === 0x10000000000000000n"); >+assert.sameValue( >+ -0xffffffffffffffffffffffffn & 0x10000000000000000n, 0n, >+ "-0xffffffffffffffffffffffffn & 0x10000000000000000n === 0n"); >+assert.sameValue( >+ 0x10000000000000000n & -0xffffffffffffffffffffffffn, 0n, >+ "0x10000000000000000n & -0xffffffffffffffffffffffffn === 0n"); >diff --git a/JSTests/stress/big-int-bitwise-and-jit.js b/JSTests/stress/big-int-bitwise-and-jit.js >new file mode 100644 >index 0000000000000000000000000000000000000000..901e91d51dde1f0fe8ada88e6f7a80adaecea8b4 >--- /dev/null >+++ b/JSTests/stress/big-int-bitwise-and-jit.js >@@ -0,0 +1,19 @@ >+//@ runBigIntEnabled >+ >+let assert = { >+ sameValue: function(i, e, m) { >+ if (i !== e) >+ throw new Error(m); >+ } >+} >+ >+function bigIntBitAnd(x, y) { >+ return x & y; >+} >+noInline(bigIntBitAnd); >+ >+for (let i = 0; i < 10000; i++) { >+ let r = bigIntBitAnd(0b11n, 0b1010n); >+ assert.sameValue(r, 0b10n, 0b11n + " & " + 0b1010n + " = " + r); >+} >+ >diff --git a/JSTests/stress/big-int-bitwise-and-memory-stress.js b/JSTests/stress/big-int-bitwise-and-memory-stress.js >new file mode 100644 >index 0000000000000000000000000000000000000000..61e7ae3b9c91c790d93bff3d458b5141f0a9454c >--- /dev/null >+++ b/JSTests/stress/big-int-bitwise-and-memory-stress.js >@@ -0,0 +1,14 @@ >+//@ runBigIntEnabled >+ >+function assert(a) { >+ if (!a) >+ throw new Error("Bad assertion"); >+} >+ >+let a = 0b11n; >+for (let i = 0; i < 1000000; i++) { >+ a &= 0b01n; >+} >+ >+assert(a === 0b01n); >+ >diff --git a/JSTests/stress/big-int-bitwise-and-to-primitive-precedence.js b/JSTests/stress/big-int-bitwise-and-to-primitive-precedence.js >new file mode 100644 >index 0000000000000000000000000000000000000000..bfa8e161fdf41798aef166475bedc1182a475977 >--- /dev/null >+++ b/JSTests/stress/big-int-bitwise-and-to-primitive-precedence.js >@@ -0,0 +1,29 @@ >+//@ runBigIntEnabled >+ >+assert = { >+ sameValue: function (input, expected, message) { >+ if (input !== expected) >+ throw new Error(message); >+ } >+}; >+ >+let o = { >+ [Symbol.toPrimitive]: function() { >+ throw new Error("Bad"); >+ } >+}; >+ >+try{ >+ o & Symbol("2"); >+ assert.sameValue(true, false, "Exception expected to be throwed, but executed without error"); >+} catch (e) { >+ assert.sameValue(e.message, "Bad", "Expected to throw Error('Bad'), but got: " + e); >+} >+ >+try{ >+ Symbol("2") & o; >+ assert.sameValue(true, false, "Exception expected to be throwed, but executed without error"); >+} catch (e) { >+ assert.sameValue(e instanceof TypeError, true, "Expected to throw TypeError, but got: " + e) >+} >+ >diff --git a/JSTests/stress/big-int-bitwise-and-type-error.js b/JSTests/stress/big-int-bitwise-and-type-error.js >new file mode 100644 >index 0000000000000000000000000000000000000000..dcb7768bac7beb1aec5b2769b76011ee41da5d1d >--- /dev/null >+++ b/JSTests/stress/big-int-bitwise-and-type-error.js >@@ -0,0 +1,106 @@ >+//@ runBigIntEnabled >+ >+function assert(a, message) { >+ if (!a) >+ throw new Error(message); >+} >+ >+function assertThrowTypeError(a, b, message) { >+ try { >+ let n = a & b; >+ assert(false, message + ": Should throw TypeError, but executed without exception"); >+ } catch (e) { >+ assert(e instanceof TypeError, message + ": expected TypeError, got: " + e); >+ } >+} >+ >+assertThrowTypeError(30n, "foo", "BigInt & String"); >+assertThrowTypeError("bar", 18757382984821n, "String & BigInt"); >+assertThrowTypeError(30n, Symbol("foo"), "BigInt & Symbol"); >+assertThrowTypeError(Symbol("bar"), 18757382984821n, "Symbol & BigInt"); >+assertThrowTypeError(30n, 3320, "BigInt & Int32"); >+assertThrowTypeError(33256, 18757382984821n, "Int32 & BigInt"); >+assertThrowTypeError(30n, 0.543, "BigInt & Double"); >+assertThrowTypeError(230.19293, 18757382984821n, "Double & BigInt"); >+assertThrowTypeError(30n, NaN, "BigInt & NaN"); >+assertThrowTypeError(NaN, 18757382984821n, "NaN & BigInt"); >+assertThrowTypeError(30n, NaN, "BigInt & NaN"); >+assertThrowTypeError(NaN, 18757382984821n, "NaN & BigInt"); >+assertThrowTypeError(30n, +Infinity, "BigInt & NaN"); >+assertThrowTypeError(+Infinity, 18757382984821n, "NaN & BigInt"); >+assertThrowTypeError(30n, -Infinity, "BigInt & -Infinity"); >+assertThrowTypeError(-Infinity, 18757382984821n, "-Infinity & BigInt"); >+assertThrowTypeError(30n, null, "BigInt & null"); >+assertThrowTypeError(null, 18757382984821n, "null & BigInt"); >+assertThrowTypeError(30n, undefined, "BigInt & undefined"); >+assertThrowTypeError(undefined, 18757382984821n, "undefined & BigInt"); >+assertThrowTypeError(30n, true, "BigInt & true"); >+assertThrowTypeError(true, 18757382984821n, "true & BigInt"); >+assertThrowTypeError(30n, false, "BigInt & false"); >+assertThrowTypeError(false, 18757382984821n, "false & BigInt"); >+ >+// Error when returning from object >+ >+let o = { >+ valueOf: function () { return Symbol("Foo"); } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt & Object.valueOf returning Symbol"); >+assertThrowTypeError(o, 18757382984821n, "Object.valueOf returning Symbol & BigInt"); >+ >+o = { >+ valueOf: function () { return 33256; } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt & Object.valueOf returning Int32"); >+assertThrowTypeError(o, 18757382984821n, "Object.valueOf returning Int32 & BigInt"); >+ >+o = { >+ valueOf: function () { return 0.453; } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt & Object.valueOf returning Double"); >+assertThrowTypeError(o, 18757382984821n, "Object.valueOf returning Double & BigInt"); >+ >+o = { >+ toString: function () { return Symbol("Foo"); } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt & Object.toString returning Symbol"); >+assertThrowTypeError(o, 18757382984821n, "Object.toString returning Symbol & BigInt"); >+ >+o = { >+ toString: function () { return 33256; } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt & Object.toString returning Int32"); >+assertThrowTypeError(o, 18757382984821n, "Object.toString returning Int32 & BigInt"); >+ >+o = { >+ toString: function () { return 0.453; } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt & Object.toString returning Double"); >+assertThrowTypeError(o, 18757382984821n, "Object.toString returning Double & BigInt"); >+ >+o = { >+ [Symbol.toPrimitive]: function () { return Symbol("Foo"); } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt & Object.@@toPrimitive returning Symbol"); >+assertThrowTypeError(o, 18757382984821n, "Object.@@toPrimitive returning Symbol & BigInt"); >+ >+o = { >+ [Symbol.toPrimitive]: function () { return 33256; } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt & Object.@@toPrimitive returning Int32"); >+assertThrowTypeError(o, 18757382984821n, "Object.@@toPrimitive returning Int32 & BigInt"); >+ >+o = { >+ [Symbol.toPrimitive]: function () { return 0.453; } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt & Object.@@toPrimitive returning Double"); >+assertThrowTypeError(o, 18757382984821n, "Object.@@toPrimitive returning Double & BigInt"); >+ >diff --git a/JSTests/stress/big-int-bitwise-and-wrapped-value.js b/JSTests/stress/big-int-bitwise-and-wrapped-value.js >new file mode 100644 >index 0000000000000000000000000000000000000000..c4377f41abd357f2079267ccb52848747d720653 >--- /dev/null >+++ b/JSTests/stress/big-int-bitwise-and-wrapped-value.js >@@ -0,0 +1,37 @@ >+//@ runBigIntEnabled >+ >+assert = { >+ sameValue: function (input, expected, message) { >+ if (input !== expected) >+ throw new Error(message); >+ } >+}; >+ >+function testBitAnd(x, y, z, message) { >+ assert.sameValue(x & y, z, message); >+ assert.sameValue(y & x, z, message); >+} >+ >+testBitAnd(Object(0b10n), 0b01n, 0b00n, "ToPrimitive: unbox object with internal slot"); >+ >+let o = { >+ [Symbol.toPrimitive]: function() { >+ return 0b10n; >+ } >+}; >+testBitAnd(o, 0b01n, 0b00n, "ToPrimitive: @@toPrimitive"); >+ >+o = { >+ valueOf: function() { >+ return 0b10n; >+ } >+}; >+testBitAnd(o, 0b01n, 0b00n, "ToPrimitive: valueOf"); >+ >+o = { >+ toString: function() { >+ return 0b10n; >+ } >+} >+testBitAnd(o, 0b01n, 0b00n, "ToPrimitive: toString"); >+
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 186228
:
341869
|
341875
|
342234
|
342235
|
342236
|
342243
|
342259
|
342278
|
344302
|
344566
|
350526
|
350532
|
351082
|
351167
|
351214