Commit e050d642 authored by oliver@apple.com's avatar oliver@apple.com

Spread operator should be performing direct "puts" and not triggering setters

https://bugs.webkit.org/show_bug.cgi?id=123047

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

Add a new opcode -- op_put_by_val_directue -- and make use of it in the spread
to array construct.  This required a new PutByValDirect node to be introduced to
the DFG.  The current implementation simply changes the slow path function that
is called, but in future this could be made faster as it does not need to check
the prototype chain.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
* bytecode/Opcode.h:
(JSC::padOpcodeName):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitDirectPutByVal):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::ArrayNode::emitBytecode):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::::executeEffects):
* dfg/DFGBackwardsPropagationPhase.cpp:
(JSC::DFG::BackwardsPropagationPhase::propagate):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::getArrayLengthElimination):
(JSC::DFG::CSEPhase::getByValLoadElimination):
(JSC::DFG::CSEPhase::checkStructureElimination):
(JSC::DFG::CSEPhase::structureTransitionWatchpointElimination):
(JSC::DFG::CSEPhase::getByOffsetLoadElimination):
(JSC::DFG::CSEPhase::putByOffsetStoreElimination):
(JSC::DFG::CSEPhase::getPropertyStorageLoadElimination):
(JSC::DFG::CSEPhase::performNodeCSE):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::clobbersWorld):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasArrayMode):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
(JSC::DFG::putByVal):
(JSC::DFG::operationPutByValInternal):
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
(JSC::DFG::PredictionPropagationPhase::doDoubleVoting):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compileContiguousPutByVal):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGTypeCheckHoistingPhase.cpp:
(JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks):
(JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
* jit/JIT.h:
(JSC::JIT::compileDirectPutByVal):
* jit/JITOperations.cpp:
* jit/JITOperations.h:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emitSlow_op_put_by_val):
(JSC::JIT::privateCompilePutByVal):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emitSlow_op_put_by_val):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LLIntSlowPaths.h:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:

LayoutTests:

Add a new testcase for the setter case.  run-javascriptcore-tests hits this with
the llint, baseline, and dfg.

* js/basic-spread-expected.txt:
* js/script-tests/basic-spread.js:
(Array):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@157656 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent ae49abfa
2013-10-18 Oliver Hunt <oliver@apple.com>
Spread operator should be performing direct "puts" and not triggering setters
https://bugs.webkit.org/show_bug.cgi?id=123047
Reviewed by Geoffrey Garen.
Add a new testcase for the setter case. run-javascriptcore-tests hits this with
the llint, baseline, and dfg.
* js/basic-spread-expected.txt:
* js/script-tests/basic-spread.js:
(Array):
2013-10-18 Dean Jackson <dino@apple.com>
Unable to upload <img src="foo.svg"> as WebGL texture
......
......@@ -93,6 +93,7 @@ PASS [,...a,4] is [,1,2,3,4]
PASS [,...a,,5] is [,1,2,3,,5]
PASS [...a.keys()] is [0,1,2]
PASS [...a.entries()].join('|') is [[0,1],[1,2],[2,3]].join('|')
PASS [...a] is [1,2,3]
PASS successfullyParsed is true
TEST COMPLETE
......
......@@ -58,4 +58,10 @@ shouldBe("[,...a,4]", "[,1,2,3,4]")
shouldBe("[,...a,,5]", "[,1,2,3,,5]")
shouldBe("[...a.keys()]", "[0,1,2]")
shouldBe("[...a.entries()].join('|')", "[[0,1],[1,2],[2,3]].join('|')")
Array.prototype.__defineSetter__(0, function(){ fail() });
Array.prototype.__defineSetter__(1, function(){ fail() });
Array.prototype.__defineSetter__(2, function(){ fail() });
shouldBe("[...a]", "[1,2,3]")
2013-10-18 Oliver Hunt <oliver@apple.com>
Spread operator should be performing direct "puts" and not triggering setters
https://bugs.webkit.org/show_bug.cgi?id=123047
Reviewed by Geoffrey Garen.
Add a new opcode -- op_put_by_val_directue -- and make use of it in the spread
to array construct. This required a new PutByValDirect node to be introduced to
the DFG. The current implementation simply changes the slow path function that
is called, but in future this could be made faster as it does not need to check
the prototype chain.
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
* bytecode/Opcode.h:
(JSC::padOpcodeName):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitDirectPutByVal):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::ArrayNode::emitBytecode):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::::executeEffects):
* dfg/DFGBackwardsPropagationPhase.cpp:
(JSC::DFG::BackwardsPropagationPhase::propagate):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::getArrayLengthElimination):
(JSC::DFG::CSEPhase::getByValLoadElimination):
(JSC::DFG::CSEPhase::checkStructureElimination):
(JSC::DFG::CSEPhase::structureTransitionWatchpointElimination):
(JSC::DFG::CSEPhase::getByOffsetLoadElimination):
(JSC::DFG::CSEPhase::putByOffsetStoreElimination):
(JSC::DFG::CSEPhase::getPropertyStorageLoadElimination):
(JSC::DFG::CSEPhase::performNodeCSE):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::clobbersWorld):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasArrayMode):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
(JSC::DFG::putByVal):
(JSC::DFG::operationPutByValInternal):
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
(JSC::DFG::PredictionPropagationPhase::doDoubleVoting):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compileContiguousPutByVal):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGTypeCheckHoistingPhase.cpp:
(JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks):
(JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
* jit/JIT.h:
(JSC::JIT::compileDirectPutByVal):
* jit/JITOperations.cpp:
* jit/JITOperations.h:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emitSlow_op_put_by_val):
(JSC::JIT::privateCompilePutByVal):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emitSlow_op_put_by_val):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LLIntSlowPaths.h:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
2013-10-18 Daniel Bates <dabates@apple.com>
[iOS] Export symbol for VM::sharedInstanceExists()
......
......@@ -1049,6 +1049,15 @@ void CodeBlock::dumpBytecode(PrintStream& out, ExecState* exec, const Instructio
dumpArrayProfiling(out, it, hasPrintedProfiling);
break;
}
case op_put_by_val_direct: {
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int r2 = (++it)->u.operand;
printLocationAndOp(out, exec, location, it, "put_by_val_direct");
out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
dumpArrayProfiling(out, it, hasPrintedProfiling);
break;
}
case op_del_by_val: {
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
......@@ -1747,6 +1756,12 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
instructions[i + opLength - 1] = &m_arrayProfiles[arrayProfileIndex];
break;
}
case op_put_by_val_direct: {
int arrayProfileIndex = pc[i + opLength - 1].u.operand;
m_arrayProfiles[arrayProfileIndex] = ArrayProfile(i);
instructions[i + opLength - 1] = &m_arrayProfiles[arrayProfileIndex];
break;
}
case op_new_array:
case op_new_array_buffer:
......
......@@ -126,6 +126,7 @@ namespace JSC {
macro(op_get_argument_by_val, 6) /* must be the same size as op_get_by_val */ \
macro(op_get_by_pname, 7) \
macro(op_put_by_val, 5) \
macro(op_put_by_val_direct, 5) \
macro(op_del_by_val, 4) \
macro(op_put_by_index, 4) \
macro(op_put_getter_setter, 5) \
......
......@@ -1413,6 +1413,17 @@ RegisterID* BytecodeGenerator::emitPutByVal(RegisterID* base, RegisterID* proper
return value;
}
RegisterID* BytecodeGenerator::emitDirectPutByVal(RegisterID* base, RegisterID* property, RegisterID* value)
{
UnlinkedArrayProfile arrayProfile = newArrayProfile();
emitOpcode(op_put_by_val_direct);
instructions().append(base->index());
instructions().append(property->index());
instructions().append(value->index());
instructions().append(arrayProfile);
return value;
}
RegisterID* BytecodeGenerator::emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
{
emitOpcode(op_del_by_val);
......
......@@ -358,6 +358,7 @@ namespace JSC {
RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
RegisterID* emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
RegisterID* emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value);
RegisterID* emitDirectPutByVal(RegisterID* base, RegisterID* property, RegisterID* value);
RegisterID* emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
RegisterID* emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value);
void emitPutGetterSetter(RegisterID* base, const Identifier& property, RegisterID* getter, RegisterID* setter);
......
......@@ -197,7 +197,7 @@ handleSpread:
RefPtr<RegisterID> index = generator.emitLoad(generator.newTemporary(), jsNumber(length));
auto spreader = [this, array, index](BytecodeGenerator& generator, RegisterID* value)
{
generator.emitPutByVal(array.get(), index.get(), value);
generator.emitDirectPutByVal(array.get(), index.get(), value);
generator.emitInc(index.get());
};
for (; n; n = n->next()) {
......@@ -207,7 +207,7 @@ handleSpread:
SpreadExpressionNode* spread = static_cast<SpreadExpressionNode*>(n->value());
generator.emitEnumeration(spread, spread->expression(), spreader);
} else {
generator.emitPutByVal(array.get(), index.get(), generator.emitNode(n->value()));
generator.emitDirectPutByVal(array.get(), index.get(), generator.emitNode(n->value()));
generator.emitInc(index.get());
}
}
......
......@@ -883,6 +883,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
break;
}
case PutByValDirect:
case PutByVal:
case PutByValAlias: {
node->setCanExit(true);
......
......@@ -347,7 +347,8 @@ private:
node->child1()->mergeFlags(flags);
break;
}
case PutByValDirect:
case PutByVal: {
m_graph.varArgChild(node, 0)->mergeFlags(NodeBytecodeUsesAsValue);
m_graph.varArgChild(node, 1)->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt);
......
......@@ -2411,6 +2411,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
NEXT_OPCODE(op_get_by_val);
}
case op_put_by_val_direct:
case op_put_by_val: {
Node* base = get(VirtualRegister(currentInstruction[1].u.operand));
......@@ -2423,7 +2424,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
addVarArgChild(property);
addVarArgChild(value);
addVarArgChild(0); // Leave room for property storage.
addToGraph(Node::VarArg, PutByVal, OpInfo(arrayMode.asWord()), OpInfo(0));
addToGraph(Node::VarArg, opcodeID == op_put_by_val_direct ? PutByValDirect : PutByVal, OpInfo(arrayMode.asWord()), OpInfo(0));
NEXT_OPCODE(op_put_by_val);
}
......
......@@ -189,6 +189,7 @@ private:
return node;
break;
case PutByValDirect:
case PutByVal:
if (!m_graph.byValIsPure(node))
return 0;
......@@ -368,6 +369,8 @@ private:
if (node->child1() == child1 && node->child2() == child2)
return node;
break;
case PutByValDirect:
case PutByVal:
case PutByValAlias: {
if (!m_graph.byValIsPure(node))
......@@ -447,7 +450,8 @@ private:
case PutByOffset:
// Setting a property cannot change the structure.
break;
case PutByValDirect:
case PutByVal:
case PutByValAlias:
if (m_graph.byValIsPure(node)) {
......@@ -494,7 +498,8 @@ private:
case PutByOffset:
// Setting a property cannot change the structure.
break;
case PutByValDirect:
case PutByVal:
case PutByValAlias:
if (m_graph.byValIsPure(node)) {
......@@ -612,7 +617,8 @@ private:
return 0;
}
break;
case PutByValDirect:
case PutByVal:
case PutByValAlias:
if (m_graph.byValIsPure(node)) {
......@@ -652,7 +658,8 @@ private:
return 0;
}
break;
case PutByValDirect:
case PutByVal:
case PutByValAlias:
case GetByVal:
......@@ -698,7 +705,8 @@ private:
// storage, so we conservatively assume that it may change the storage
// pointer of any object, including ours.
return 0;
case PutByValDirect:
case PutByVal:
case PutByValAlias:
if (m_graph.byValIsPure(node)) {
......@@ -1252,7 +1260,8 @@ private:
if (m_graph.byValIsPure(node))
setReplacement(getByValLoadElimination(node->child1().node(), node->child2().node()));
break;
case PutByValDirect:
case PutByVal: {
if (cseMode == StoreElimination)
break;
......
......@@ -121,6 +121,7 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, Instruc
case op_nstricteq:
case op_get_by_val:
case op_put_by_val:
case op_put_by_val_direct:
case op_get_by_id:
case op_get_by_id_out_of_line:
case op_get_array_length:
......
......@@ -311,7 +311,8 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write
RELEASE_ASSERT_NOT_REACHED();
return;
}
case PutByValDirect:
case PutByVal:
case PutByValAlias: {
ArrayMode mode = node->arrayMode();
......
......@@ -473,7 +473,8 @@ private:
break;
}
case PutByValDirect:
case PutByVal:
case PutByValAlias: {
Edge& child1 = m_graph.varArgChild(node, 0);
......
......@@ -631,6 +631,7 @@ public:
case CompareEq:
return !isPredictedNumerical(node);
case GetByVal:
case PutByValDirect:
case PutByVal:
case PutByValAlias:
return !byValIsPure(node);
......
......@@ -1071,6 +1071,7 @@ struct Node {
switch (op()) {
case GetIndexedPropertyStorage:
case GetArrayLength:
case PutByValDirect:
case PutByVal:
case PutByValAlias:
case GetByVal:
......
......@@ -140,6 +140,7 @@ namespace JSC { namespace DFG {
/* this must be the directly subsequent property put. Note that PutByVal */\
/* opcodes use VarArgs beause they may have up to 4 children. */\
macro(GetByVal, NodeResultJS | NodeMustGenerate | NodeMightClobber) \
macro(PutByValDirect, NodeMustGenerate | NodeHasVarArgs | NodeMightClobber) \
macro(PutByVal, NodeMustGenerate | NodeHasVarArgs | NodeMightClobber) \
macro(PutByValAlias, NodeMustGenerate | NodeHasVarArgs | NodeMightClobber) \
macro(GetById, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
......
......@@ -61,12 +61,16 @@
namespace JSC { namespace DFG {
template<bool strict>
template<bool strict, bool direct>
static inline void putByVal(ExecState* exec, JSValue baseValue, uint32_t index, JSValue value)
{
VM& vm = exec->vm();
NativeCallFrameTracer tracer(&vm, exec);
if (direct) {
RELEASE_ASSERT(baseValue.isObject());
asObject(baseValue)->putDirectIndex(exec, index, value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
return;
}
if (baseValue.isObject()) {
JSObject* object = asObject(baseValue);
if (object->canSetIndexQuickly(index)) {
......@@ -81,7 +85,7 @@ static inline void putByVal(ExecState* exec, JSValue baseValue, uint32_t index,
baseValue.putByIndex(exec, index, value, strict);
}
template<bool strict>
template<bool strict, bool direct>
ALWAYS_INLINE static void JIT_OPERATION operationPutByValInternal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
{
VM* vm = &exec->vm();
......@@ -92,7 +96,7 @@ ALWAYS_INLINE static void JIT_OPERATION operationPutByValInternal(ExecState* exe
JSValue value = JSValue::decode(encodedValue);
if (LIKELY(property.isUInt32())) {
putByVal<strict>(exec, baseValue, property.asUInt32(), value);
putByVal<strict, direct>(exec, baseValue, property.asUInt32(), value);
return;
}
......@@ -100,14 +104,18 @@ ALWAYS_INLINE static void JIT_OPERATION operationPutByValInternal(ExecState* exe
double propertyAsDouble = property.asDouble();
uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
if (propertyAsDouble == propertyAsUInt32) {
putByVal<strict>(exec, baseValue, propertyAsUInt32, value);
putByVal<strict, direct>(exec, baseValue, propertyAsUInt32, value);
return;
}
}
if (isName(property)) {
PutPropertySlot slot(strict);
baseValue.put(exec, jsCast<NameInstance*>(property.asCell())->privateName(), value, slot);
if (direct) {
RELEASE_ASSERT(baseValue.isObject());
asObject(baseValue)->putDirect(*vm, jsCast<NameInstance*>(property.asCell())->privateName(), value, slot);
} else
baseValue.put(exec, jsCast<NameInstance*>(property.asCell())->privateName(), value, slot);
return;
}
......@@ -115,7 +123,11 @@ ALWAYS_INLINE static void JIT_OPERATION operationPutByValInternal(ExecState* exe
Identifier ident(exec, property.toString(exec)->value(exec));
if (!vm->exception()) {
PutPropertySlot slot(strict);
baseValue.put(exec, ident, value, slot);
if (direct) {
RELEASE_ASSERT(baseValue.isObject());
asObject(baseValue)->putDirect(*vm, jsCast<NameInstance*>(property.asCell())->privateName(), value, slot);
} else
baseValue.put(exec, ident, value, slot);
}
}
......@@ -350,7 +362,7 @@ void JIT_OPERATION operationPutByValStrict(ExecState* exec, EncodedJSValue encod
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);
operationPutByValInternal<true>(exec, encodedBase, encodedProperty, encodedValue);
operationPutByValInternal<true, false>(exec, encodedBase, encodedProperty, encodedValue);
}
void JIT_OPERATION operationPutByValNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
......@@ -358,7 +370,7 @@ void JIT_OPERATION operationPutByValNonStrict(ExecState* exec, EncodedJSValue en
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);
operationPutByValInternal<false>(exec, encodedBase, encodedProperty, encodedValue);
operationPutByValInternal<false, false>(exec, encodedBase, encodedProperty, encodedValue);
}
void JIT_OPERATION operationPutByValCellStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
......@@ -366,7 +378,7 @@ void JIT_OPERATION operationPutByValCellStrict(ExecState* exec, JSCell* cell, En
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);
operationPutByValInternal<true>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
operationPutByValInternal<true, false>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
}
void JIT_OPERATION operationPutByValCellNonStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
......@@ -374,7 +386,7 @@ void JIT_OPERATION operationPutByValCellNonStrict(ExecState* exec, JSCell* cell,
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);
operationPutByValInternal<false>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
operationPutByValInternal<false, false>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
}
void JIT_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue)
......@@ -441,6 +453,65 @@ void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState*
array, exec, Identifier::from(exec, index), jsValue, slot);
}
void JIT_OPERATION operationPutByValDirectStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
{
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);
operationPutByValInternal<true, true>(exec, encodedBase, encodedProperty, encodedValue);
}
void JIT_OPERATION operationPutByValDirectNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
{
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);
operationPutByValInternal<false, true>(exec, encodedBase, encodedProperty, encodedValue);
}
void JIT_OPERATION operationPutByValDirectCellStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
{
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);
operationPutByValInternal<true, true>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
}
void JIT_OPERATION operationPutByValDirectCellNonStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
{
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);
operationPutByValInternal<false, true>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
}
void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue)
{
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);
if (index >= 0) {
array->putDirectIndex(exec, index, JSValue::decode(encodedValue), 0, PutDirectIndexShouldThrow);
return;
}
PutPropertySlot slot(true);
array->putDirect(exec->vm(), Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
}
void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue)
{
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);
if (index >= 0) {
array->putDirectIndex(exec, index, JSValue::decode(encodedValue));
return;
}
PutPropertySlot slot(false);
array->putDirect(exec->vm(), Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
}
EncodedJSValue JIT_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue encodedValue, JSArray* array)
{
VM* vm = &exec->vm();
......
......@@ -79,6 +79,13 @@ void JIT_OPERATION operationPutByValCellStrict(ExecState*, JSCell*, EncodedJSVal
void JIT_OPERATION operationPutByValCellNonStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL;
void JIT_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState*, JSObject*, int32_t index, EncodedJSValue encodedValue) WTF_INTERNAL;
void JIT_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState*, JSObject*, int32_t index, EncodedJSValue encodedValue) WTF_INTERNAL;
void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsNonStrict(ExecState*, JSObject*, int32_t index, EncodedJSValue encodedValue) WTF_INTERNAL;
void JIT_OPERATION operationPutByValDirectStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL;
void JIT_OPERATION operationPutByValDirectNonStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL;
void JIT_OPERATION operationPutByValDirectCellStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL;
void JIT_OPERATION operationPutByValDirectCellNonStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL;
void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsStrict(ExecState*, JSObject*, int32_t index, EncodedJSValue encodedValue) WTF_INTERNAL;
void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsNonStrict(ExecState*, JSObject*, int32_t index, EncodedJSValue encodedValue) WTF_INTERNAL;
void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsStrict(ExecState*, JSObject*, int32_t index, double value) WTF_INTERNAL;
void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState*, JSObject*, int32_t index, double value) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationArrayPush(ExecState*, EncodedJSValue encodedValue, JSArray*) WTF_INTERNAL;
......
......@@ -545,6 +545,7 @@ private:
#ifndef NDEBUG
// These get ignored because they don't return anything.
case PutByValDirect:
case PutByVal:
case PutClosureVar:
case Return:
......@@ -726,7 +727,8 @@ private:
node->variableAccessData()->vote(VoteValue);
break;
}
case PutByValDirect:
case PutByVal:
case PutByValAlias: {
Edge child1 = m_graph.varArgChild(node, 0);
......
......@@ -253,7 +253,8 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
case GetTypedArrayByteOffset:
return !(state.forNode(node->child1()).m_type & ~(SpecTypedArrayView));
case PutByValDirect:
case PutByVal:
case PutByValAlias:
return node->arrayMode().modeForPut().alreadyChecked(
......
<
......@@ -1866,11 +1866,17 @@ void SpeculativeJIT::compileContiguousPutByVal(Node* node, BaseOperandType& base
storage.use();
if (arrayMode.isOutOfBounds()) {
addSlowPathGenerator(
slowPathCall(
if (node->op() == PutByValDirect) {
addSlowPathGenerator(slowPathCall(
slowCase, this,
m_jit.codeBlock()->isStrictMode() ? operationPutByValDirectBeyondArrayBoundsStrict : operationPutByValDirectBeyondArrayBoundsNonStrict,
NoResult, baseReg, propertyReg, valueTag, valuePayloadReg));
} else {
addSlowPathGenerator(slowPathCall(
slowCase, this,
m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict,
NoResult, baseReg, propertyReg, valueTag, valuePayloadReg));
}
}
noResult(node, UseChildrenCalledExplicitly);