Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (200458 => 200459)
--- trunk/Source/_javascript_Core/ChangeLog 2016-05-05 17:14:49 UTC (rev 200458)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-05-05 17:30:02 UTC (rev 200459)
@@ -1,3 +1,56 @@
+2016-05-05 Keith Miller <[email protected]>
+
+ Add support for delete by value to the DFG
+ https://bugs.webkit.org/show_bug.cgi?id=157372
+
+ Reviewed by Filip Pizlo.
+
+ This patch adds basic support for delete by value to the DFG. delete by value
+ just calls out to a C++ operation on each execution. Additionally, this patch
+ fixes an issue with delete by id where we would crash if the base was null
+ or undefined.
+
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ * dfg/DFGCapabilities.cpp:
+ (JSC::DFG::capabilityLevel):
+ * dfg/DFGClobberize.h:
+ (JSC::DFG::clobberize):
+ * dfg/DFGDoesGC.cpp:
+ (JSC::DFG::doesGC):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGNodeType.h:
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ * dfg/DFGSafeToExecute.h:
+ (JSC::DFG::safeToExecute):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileDeleteById):
+ (JSC::DFG::SpeculativeJIT::compileDeleteByVal):
+ * dfg/DFGSpeculativeJIT.h:
+ (JSC::DFG::SpeculativeJIT::callOperation):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * jit/JIT.cpp:
+ (JSC::JIT::privateCompileMainPass):
+ * jit/JIT.h:
+ * jit/JITOperations.cpp:
+ * jit/JITOperations.h:
+ * jit/JITPropertyAccess.cpp:
+ (JSC::JIT::emit_op_del_by_val):
+ * jit/JITPropertyAccess32_64.cpp:
+ (JSC::JIT::emit_op_del_by_val):
+ * tests/stress/delete-by-val.js: Added.
+ (assert):
+ (test):
+ * tests/stress/delete-to-object-exception.js: Added.
+ (assert):
+ (test):
+
2016-05-05 Michael Saboff <[email protected]>
Unreviewed build fix after change set r200447.
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (200458 => 200459)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2016-05-05 17:14:49 UTC (rev 200458)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2016-05-05 17:30:02 UTC (rev 200459)
@@ -2191,7 +2191,8 @@
break;
}
- case DeleteById: {
+ case DeleteById:
+ case DeleteByVal: {
// FIXME: This could decide if the delete will be successful based on the set of structures that
// we get from our base value. https://bugs.webkit.org/show_bug.cgi?id=156611
clobberWorld(node->origin.semantic, clobberLimit);
Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (200458 => 200459)
--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2016-05-05 17:14:49 UTC (rev 200458)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2016-05-05 17:30:02 UTC (rev 200459)
@@ -4160,6 +4160,14 @@
NEXT_OPCODE(op_del_by_id);
}
+ case op_del_by_val: {
+ int dst = currentInstruction[1].u.operand;
+ Node* base = get(VirtualRegister(currentInstruction[2].u.operand));
+ Node* key = get(VirtualRegister(currentInstruction[3].u.operand));
+ set(VirtualRegister(dst), addToGraph(DeleteByVal, base, key));
+ NEXT_OPCODE(op_del_by_val);
+ }
+
case op_profile_type: {
Node* valueToProfile = get(VirtualRegister(currentInstruction[1].u.operand));
addToGraph(ProfileType, OpInfo(currentInstruction[2].u.location), valueToProfile);
Modified: trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp (200458 => 200459)
--- trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp 2016-05-05 17:14:49 UTC (rev 200458)
+++ trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp 2016-05-05 17:30:02 UTC (rev 200459)
@@ -164,6 +164,7 @@
case op_put_getter_by_val:
case op_put_setter_by_val:
case op_del_by_id:
+ case op_del_by_val:
case op_jmp:
case op_jtrue:
case op_jfalse:
Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (200458 => 200459)
--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2016-05-05 17:14:49 UTC (rev 200458)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2016-05-05 17:30:02 UTC (rev 200459)
@@ -448,6 +448,7 @@
case PutGetterByVal:
case PutSetterByVal:
case DeleteById:
+ case DeleteByVal:
case ArrayPush:
case ArrayPop:
case Call:
Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (200458 => 200459)
--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2016-05-05 17:14:49 UTC (rev 200458)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2016-05-05 17:30:02 UTC (rev 200459)
@@ -108,6 +108,7 @@
case PutGetterByVal:
case PutSetterByVal:
case DeleteById:
+ case DeleteByVal:
case CheckStructure:
case GetExecutable:
case GetButterfly:
Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (200458 => 200459)
--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2016-05-05 17:14:49 UTC (rev 200458)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2016-05-05 17:30:02 UTC (rev 200459)
@@ -1541,6 +1541,7 @@
case ProfileWillCall:
case ProfileDidCall:
case DeleteById:
+ case DeleteByVal:
case IsArrayObject:
case IsJSArray:
case IsArrayConstructor:
Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (200458 => 200459)
--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2016-05-05 17:14:49 UTC (rev 200458)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2016-05-05 17:30:02 UTC (rev 200459)
@@ -195,6 +195,7 @@
macro(PutGetterByVal, NodeMustGenerate) \
macro(PutSetterByVal, NodeMustGenerate) \
macro(DeleteById, NodeResultBoolean | NodeMustGenerate) \
+ macro(DeleteByVal, NodeResultBoolean | NodeMustGenerate) \
macro(CheckStructure, NodeMustGenerate) \
macro(GetExecutable, NodeResultJS) \
macro(PutStructure, NodeMustGenerate) \
Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (200458 => 200459)
--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2016-05-05 17:14:49 UTC (rev 200458)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2016-05-05 17:30:02 UTC (rev 200459)
@@ -751,6 +751,7 @@
setPrediction(SpecDoubleReal);
break;
}
+ case DeleteByVal:
case DeleteById:
case LogicalNot:
case CompareLess:
Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (200458 => 200459)
--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2016-05-05 17:14:49 UTC (rev 200458)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2016-05-05 17:30:02 UTC (rev 200459)
@@ -193,6 +193,7 @@
case ValueAdd:
case TryGetById:
case DeleteById:
+ case DeleteByVal:
case GetById:
case GetByIdFlush:
case PutById:
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (200458 => 200459)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2016-05-05 17:14:49 UTC (rev 200458)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2016-05-05 17:30:02 UTC (rev 200459)
@@ -1072,6 +1072,26 @@
unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
}
+void SpeculativeJIT::compileDeleteByVal(Node* node)
+{
+ JSValueOperand base(this, node->child1());
+ JSValueOperand key(this, node->child2());
+ GPRFlushedCallResult result(this);
+
+ JSValueRegs baseRegs = base.jsValueRegs();
+ JSValueRegs keyRegs = key.jsValueRegs();
+ GPRReg resultGPR = result.gpr();
+
+ base.use();
+ key.use();
+
+ flushRegisters();
+ callOperation(operationDeleteByVal, resultGPR, baseRegs, keyRegs);
+ m_jit.exceptionCheck();
+
+ unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
+}
+
bool SpeculativeJIT::nonSpeculativeCompare(Node* node, MacroAssembler::RelationalCondition cond, S_JITOperation_EJJ helperFunction)
{
unsigned branchIndexInBlock = detectPeepHoleBranch();
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (200458 => 200459)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2016-05-05 17:14:49 UTC (rev 200458)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2016-05-05 17:30:02 UTC (rev 200459)
@@ -715,6 +715,7 @@
#endif
void compileDeleteById(Node*);
+ void compileDeleteByVal(Node*);
void compileTryGetById(Node*);
void compileIn(Node*);
@@ -1511,6 +1512,10 @@
m_jit.setupArgumentsWithExecState(arg1, arg2);
return appendCallSetResult(operation, result);
}
+ JITCompiler::Call callOperation(S_JITOperation_EJJ operation, GPRReg result, JSValueRegs arg1, JSValueRegs arg2)
+ {
+ return callOperation(operation, result, arg1.gpr(), arg2.gpr());
+ }
JITCompiler::Call callOperation(S_JITOperation_EGJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
{
m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
@@ -1946,6 +1951,12 @@
m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, SH4_32BIT_DUMMY_ARG arg2Payload, arg2Tag);
return appendCallSetResult(operation, result);
}
+
+ JITCompiler::Call callOperation(S_JITOperation_EJJ operation, GPRReg result, JSValueRegs arg1, JSValueRegs arg2)
+ {
+ return callOperation(operation, result, arg1.tagGPR(), arg1.payloadGPR(), arg2.tagGPR(), arg2.payloadGPR());
+ }
+
JITCompiler::Call callOperation(S_JITOperation_EGJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2Tag, GPRReg arg2Payload, GPRReg arg3Tag, GPRReg arg3Payload)
{
m_jit.setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag, SH4_32BIT_DUMMY_ARG arg3Payload, arg3Tag);
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (200458 => 200459)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2016-05-05 17:14:49 UTC (rev 200458)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2016-05-05 17:30:02 UTC (rev 200459)
@@ -4102,6 +4102,11 @@
compileDeleteById(node);
break;
}
+
+ case DeleteByVal: {
+ compileDeleteByVal(node);
+ break;
+ }
case CheckCell: {
SpeculateCellOperand cell(this, node->child1());
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (200458 => 200459)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2016-05-05 17:14:49 UTC (rev 200458)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2016-05-05 17:30:02 UTC (rev 200459)
@@ -4143,6 +4143,11 @@
compileDeleteById(node);
break;
}
+
+ case DeleteByVal: {
+ compileDeleteByVal(node);
+ break;
+ }
case CheckCell: {
SpeculateCellOperand cell(this, node->child1());
Modified: trunk/Source/_javascript_Core/jit/JIT.cpp (200458 => 200459)
--- trunk/Source/_javascript_Core/jit/JIT.cpp 2016-05-05 17:14:49 UTC (rev 200458)
+++ trunk/Source/_javascript_Core/jit/JIT.cpp 2016-05-05 17:30:02 UTC (rev 200459)
@@ -187,7 +187,6 @@
unsigned bytecodeOffset = m_bytecodeOffset;
switch (opcodeID) {
- DEFINE_SLOW_OP(del_by_val)
DEFINE_SLOW_OP(in)
DEFINE_SLOW_OP(less)
DEFINE_SLOW_OP(lesseq)
@@ -222,6 +221,7 @@
DEFINE_OP(op_resume)
DEFINE_OP(op_debug)
DEFINE_OP(op_del_by_id)
+ DEFINE_OP(op_del_by_val)
DEFINE_OP(op_div)
DEFINE_OP(op_end)
DEFINE_OP(op_enter)
Modified: trunk/Source/_javascript_Core/jit/JIT.h (200458 => 200459)
--- trunk/Source/_javascript_Core/jit/JIT.h 2016-05-05 17:14:49 UTC (rev 200458)
+++ trunk/Source/_javascript_Core/jit/JIT.h 2016-05-05 17:30:02 UTC (rev 200459)
@@ -496,6 +496,7 @@
void emit_op_resume(Instruction*);
void emit_op_debug(Instruction*);
void emit_op_del_by_id(Instruction*);
+ void emit_op_del_by_val(Instruction*);
void emit_op_div(Instruction*);
void emit_op_end(Instruction*);
void emit_op_enter(Instruction*);
Modified: trunk/Source/_javascript_Core/jit/JITOperations.cpp (200458 => 200459)
--- trunk/Source/_javascript_Core/jit/JITOperations.cpp 2016-05-05 17:14:49 UTC (rev 200458)
+++ trunk/Source/_javascript_Core/jit/JITOperations.cpp 2016-05-05 17:30:02 UTC (rev 200459)
@@ -1871,7 +1871,6 @@
return JSValue::encode(jsBoolean(operationDeleteById(exec, base, uid)));
}
-
size_t JIT_OPERATION operationDeleteById(ExecState* exec, EncodedJSValue encodedBase, UniquedStringImpl* uid)
{
VM& vm = exec->vm();
@@ -1879,13 +1878,45 @@
JSObject* baseObj = JSValue::decode(encodedBase).toObject(exec);
if (!baseObj)
- JSValue::encode(JSValue());
+ return false;
bool couldDelete = baseObj->methodTable(vm)->deleteProperty(baseObj, exec, Identifier::fromUid(&vm, uid));
if (!couldDelete && exec->codeBlock()->isStrictMode())
vm.throwException(exec, createTypeError(exec, ASCIILiteral("Unable to delete property.")));
return couldDelete;
}
+EncodedJSValue JIT_OPERATION operationDeleteByValJSResult(ExecState* exec, EncodedJSValue base, EncodedJSValue key)
+{
+ return JSValue::encode(jsBoolean(operationDeleteByVal(exec, base, key)));
+}
+
+size_t JIT_OPERATION operationDeleteByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedKey)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+
+ JSObject* baseObj = JSValue::decode(encodedBase).toObject(exec);
+ JSValue key = JSValue::decode(encodedKey);
+ if (!baseObj)
+ return false;
+
+ bool couldDelete;
+ uint32_t index;
+ if (key.getUInt32(index))
+ couldDelete = baseObj->methodTable(vm)->deletePropertyByIndex(baseObj, exec, index);
+ else {
+ if (vm.exception())
+ return false;
+ Identifier property = key.toPropertyKey(exec);
+ if (vm.exception())
+ return false;
+ couldDelete = baseObj->methodTable(vm)->deleteProperty(baseObj, exec, property);
+ }
+ if (!couldDelete && exec->codeBlock()->isStrictMode())
+ vm.throwException(exec, createTypeError(exec, ASCIILiteral("Unable to delete property.")));
+ return couldDelete;
+}
+
EncodedJSValue JIT_OPERATION operationInstanceOf(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedProto)
{
VM& vm = exec->vm();
Modified: trunk/Source/_javascript_Core/jit/JITOperations.h (200458 => 200459)
--- trunk/Source/_javascript_Core/jit/JITOperations.h 2016-05-05 17:14:49 UTC (rev 200458)
+++ trunk/Source/_javascript_Core/jit/JITOperations.h 2016-05-05 17:30:02 UTC (rev 200459)
@@ -373,6 +373,8 @@
EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo*) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationDeleteByIdJSResult(ExecState*, EncodedJSValue base, UniquedStringImpl*) WTF_INTERNAL;
size_t JIT_OPERATION operationDeleteById(ExecState*, EncodedJSValue base, UniquedStringImpl*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationDeleteByValJSResult(ExecState*, EncodedJSValue base, EncodedJSValue target) WTF_INTERNAL;
+size_t JIT_OPERATION operationDeleteByVal(ExecState*, EncodedJSValue base, EncodedJSValue target) WTF_INTERNAL;
JSCell* JIT_OPERATION operationGetPNames(ExecState*, JSObject*) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationInstanceOf(ExecState*, EncodedJSValue, EncodedJSValue proto) WTF_INTERNAL;
int32_t JIT_OPERATION operationSizeFrameForVarargs(ExecState*, EncodedJSValue arguments, int32_t numUsedStackSlots, int32_t firstVarArgOffset) WTF_INTERNAL;
Modified: trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp (200458 => 200459)
--- trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp 2016-05-05 17:14:49 UTC (rev 200458)
+++ trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp 2016-05-05 17:30:02 UTC (rev 200459)
@@ -532,6 +532,16 @@
callOperation(operationDeleteByIdJSResult, dst, regT0, m_codeBlock->identifier(property).impl());
}
+void JIT::emit_op_del_by_val(Instruction* currentInstruction)
+{
+ int dst = currentInstruction[1].u.operand;
+ int base = currentInstruction[2].u.operand;
+ int property = currentInstruction[3].u.operand;
+ emitGetVirtualRegister(base, regT0);
+ emitGetVirtualRegister(property, regT1);
+ callOperation(operationDeleteByValJSResult, dst, regT0, regT1);
+}
+
void JIT::emit_op_try_get_by_id(Instruction* currentInstruction)
{
int resultVReg = currentInstruction[1].u.operand;
Modified: trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp (200458 => 200459)
--- trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp 2016-05-05 17:14:49 UTC (rev 200458)
+++ trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp 2016-05-05 17:30:02 UTC (rev 200459)
@@ -130,6 +130,15 @@
callOperation(operationDeleteByIdJSResult, dst, regT1, regT0, m_codeBlock->identifier(property).impl());
}
+void JIT::emit_op_del_by_val(Instruction* currentInstruction)
+{
+ int dst = currentInstruction[1].u.operand;
+ int base = currentInstruction[2].u.operand;
+ int property = currentInstruction[3].u.operand;
+ emitLoad2(base, regT1, regT0, property, regT3, regT2);
+ callOperation(operationDeleteByValJSResult, dst, regT1, regT0, regT3, regT2);
+}
+
JIT::CodeRef JIT::stringGetByValStubGenerator(VM* vm)
{
JSInterfaceJIT jit(vm);
Added: trunk/Source/_javascript_Core/tests/stress/delete-by-val.js (0 => 200459)
--- trunk/Source/_javascript_Core/tests/stress/delete-by-val.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/delete-by-val.js 2016-05-05 17:30:02 UTC (rev 200459)
@@ -0,0 +1,15 @@
+function assert(condition) {
+ if (!condition)
+ throw new Error("assertion failed");
+}
+
+function test(i) {
+ let foo = {};
+ foo["bar" + i] = 1;
+ assert(foo["bar" + i] === 1)
+ assert(delete foo["bar" + i]);
+ assert(!("bar" + i in foo));
+}
+
+for (let i = 0; i < 100000; ++i)
+ test(i);
Added: trunk/Source/_javascript_Core/tests/stress/delete-to-object-exception.js (0 => 200459)
--- trunk/Source/_javascript_Core/tests/stress/delete-to-object-exception.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/delete-to-object-exception.js 2016-05-05 17:30:02 UTC (rev 200459)
@@ -0,0 +1,24 @@
+function assert(condition) {
+ if (!condition)
+ throw new Error("assertion failed");
+}
+
+function test(i) {
+ let value = null;
+ let passed = true;
+
+ try {
+ delete value.bar;
+ passed = false;
+ } catch(e) {}
+ try {
+ delete value["bar" + i];
+ passed = false;
+ } catch(e) {}
+ if (!passed)
+ throw new Error("didn't throw");
+}
+noInline(test);
+
+for (let i = 0; i < 10000; ++i)
+ test();