Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (202626 => 202627)
--- trunk/Source/_javascript_Core/ChangeLog 2016-06-29 16:50:21 UTC (rev 202626)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-06-29 16:53:25 UTC (rev 202627)
@@ -1,3 +1,44 @@
+2016-06-29 Caio Lima <ticaiol...@gmail.com>
+
+ LLInt should support other types of prototype GetById caching.
+ https://bugs.webkit.org/show_bug.cgi?id=158083
+
+ Recently, we started supporting prototype load caching for get_by_id
+ in the LLInt. This patch is expading the caching strategy to enable
+ cache the prototype accessor and custom acessors.
+
+ Similarly to the get_by_id_proto_load bytecode, we are adding new
+ bytecodes called get_by_id_proto_accessor that uses the calculated
+ offset of a object to call a getter function and get_by_id_proto_custom
+ that stores the pointer to the custom function and call them directly
+ from LowLevelInterpreter.
+
+ Reviewed by Keith Miller
+
+ * bytecode/BytecodeList.json:
+ * bytecode/BytecodeUseDef.h:
+ (JSC::computeUsesForBytecodeOffset):
+ (JSC::computeDefsForBytecodeOffset):
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::printGetByIdOp):
+ (JSC::CodeBlock::dumpBytecode):
+ (JSC::CodeBlock::finalizeLLIntInlineCaches):
+ * bytecode/GetByIdStatus.cpp:
+ (JSC::GetByIdStatus::computeFromLLInt):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ * dfg/DFGCapabilities.cpp:
+ (JSC::DFG::capabilityLevel):
+ * jit/JIT.cpp:
+ (JSC::JIT::privateCompileMainPass):
+ (JSC::JIT::privateCompileSlowCases):
+ * llint/LLIntSlowPaths.cpp:
+ (JSC::LLInt::setupGetByIdPrototypeCache):
+ (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+ * llint/LLIntSlowPaths.h:
+ * llint/LowLevelInterpreter32_64.asm:
+ * llint/LowLevelInterpreter64.asm:
+
2016-06-28 Commit Queue <commit-qu...@webkit.org>
Unreviewed, rolling out r202580.
Modified: trunk/Source/_javascript_Core/bytecode/BytecodeList.json (202626 => 202627)
--- trunk/Source/_javascript_Core/bytecode/BytecodeList.json 2016-06-29 16:50:21 UTC (rev 202626)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeList.json 2016-06-29 16:53:25 UTC (rev 202627)
@@ -64,6 +64,8 @@
{ "name" : "op_get_by_id", "length" : 9 },
{ "name" : "op_get_by_id_proto_load", "length" : 9 },
{ "name" : "op_get_by_id_unset", "length" : 9 },
+ { "name" : "op_get_by_id_proto_accessor", "length" : 9 },
+ { "name" : "op_get_by_id_proto_custom", "length" : 9 },
{ "name" : "op_get_by_id_with_this", "length" : 5 },
{ "name" : "op_get_by_val_with_this", "length" : 5 },
{ "name" : "op_try_get_by_id", "length" : 4 },
Modified: trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h (202626 => 202627)
--- trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h 2016-06-29 16:50:21 UTC (rev 202626)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h 2016-06-29 16:53:25 UTC (rev 202627)
@@ -164,6 +164,8 @@
case op_get_by_id:
case op_get_by_id_proto_load:
case op_get_by_id_unset:
+ case op_get_by_id_proto_accessor:
+ case op_get_by_id_proto_custom:
case op_get_array_length:
case op_typeof:
case op_is_empty:
@@ -403,6 +405,8 @@
case op_get_by_id:
case op_get_by_id_proto_load:
case op_get_by_id_unset:
+ case op_get_by_id_proto_accessor:
+ case op_get_by_id_proto_custom:
case op_get_by_id_with_this:
case op_get_by_val_with_this:
case op_get_array_length:
Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp (202626 => 202627)
--- trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp 2016-06-29 16:50:21 UTC (rev 202626)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp 2016-06-29 16:53:25 UTC (rev 202627)
@@ -354,6 +354,12 @@
case op_get_by_id_unset:
op = "get_by_id_unset";
break;
+ case op_get_by_id_proto_accessor:
+ op = "op_get_by_id_proto_accessor";
+ break;
+ case op_get_by_id_proto_custom:
+ op = "op_get_by_id_proto_custom";
+ break;
case op_get_array_length:
op = "array_length";
break;
@@ -1137,6 +1143,8 @@
case op_get_by_id:
case op_get_by_id_proto_load:
case op_get_by_id_unset:
+ case op_get_by_id_proto_accessor:
+ case op_get_by_id_proto_custom:
case op_get_array_length: {
printGetByIdOp(out, exec, location, it);
printGetByIdCacheStatus(out, exec, location, stubInfos);
@@ -2796,7 +2804,9 @@
switch (interpreter->getOpcodeID(curInstruction[0].u.opcode)) {
case op_get_by_id:
case op_get_by_id_proto_load:
- case op_get_by_id_unset: {
+ case op_get_by_id_unset:
+ case op_get_by_id_proto_accessor:
+ case op_get_by_id_proto_custom: {
StructureID oldStructureID = curInstruction[4].u.structureID;
if (!oldStructureID || Heap::isMarked(m_vm->heap.structureIDTable().get(oldStructureID)))
break;
Modified: trunk/Source/_javascript_Core/bytecode/GetByIdStatus.cpp (202626 => 202627)
--- trunk/Source/_javascript_Core/bytecode/GetByIdStatus.cpp 2016-06-29 16:50:21 UTC (rev 202626)
+++ trunk/Source/_javascript_Core/bytecode/GetByIdStatus.cpp 2016-06-29 16:53:25 UTC (rev 202627)
@@ -78,7 +78,7 @@
Opcode opcode = instruction[0].u.opcode;
- ASSERT(opcode == LLInt::getOpcode(op_get_array_length) || opcode == LLInt::getOpcode(op_try_get_by_id) || opcode == LLInt::getOpcode(op_get_by_id_proto_load) || opcode == LLInt::getOpcode(op_get_by_id) || opcode == LLInt::getOpcode(op_get_by_id_unset));
+ ASSERT(opcode == LLInt::getOpcode(op_get_array_length) || opcode == LLInt::getOpcode(op_try_get_by_id) || opcode == LLInt::getOpcode(op_get_by_id_proto_load) || opcode == LLInt::getOpcode(op_get_by_id) || opcode == LLInt::getOpcode(op_get_by_id_unset) || opcode == LLInt::getOpcode(op_get_by_id_proto_accessor) || opcode == LLInt::getOpcode(op_get_by_id_proto_custom));
// FIXME: We should not just bail if we see a try_get_by_id or a get_by_id_proto_load.
// https://bugs.webkit.org/show_bug.cgi?id=158039
Modified: trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.h (202626 => 202627)
--- trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.h 2016-06-29 16:50:21 UTC (rev 202626)
+++ trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.h 2016-06-29 16:53:25 UTC (rev 202627)
@@ -107,6 +107,7 @@
};
class UnlinkedCodeBlock : public JSCell {
+ friend class LLIntOffsetsExtractor;
public:
typedef JSCell Base;
static const unsigned StructureFlags = Base::StructureFlags;
Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (202626 => 202627)
--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2016-06-29 16:50:21 UTC (rev 202626)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2016-06-29 16:53:25 UTC (rev 202627)
@@ -4145,6 +4145,8 @@
case op_get_by_id:
case op_get_by_id_proto_load:
case op_get_by_id_unset:
+ case op_get_by_id_proto_accessor:
+ case op_get_by_id_proto_custom:
case op_get_array_length: {
SpeculatedType prediction = getPrediction();
Modified: trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp (202626 => 202627)
--- trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp 2016-06-29 16:50:21 UTC (rev 202626)
+++ trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp 2016-06-29 16:53:25 UTC (rev 202627)
@@ -158,6 +158,8 @@
case op_get_by_id:
case op_get_by_id_proto_load:
case op_get_by_id_unset:
+ case op_get_by_id_proto_accessor:
+ case op_get_by_id_proto_custom:
case op_get_by_id_with_this:
case op_get_by_val_with_this:
case op_get_array_length:
Modified: trunk/Source/_javascript_Core/jit/JIT.cpp (202626 => 202627)
--- trunk/Source/_javascript_Core/jit/JIT.cpp 2016-06-29 16:50:21 UTC (rev 202626)
+++ trunk/Source/_javascript_Core/jit/JIT.cpp 2016-06-29 16:53:25 UTC (rev 202627)
@@ -250,6 +250,8 @@
case op_get_array_length:
case op_get_by_id_proto_load:
case op_get_by_id_unset:
+ case op_get_by_id_proto_accessor:
+ case op_get_by_id_proto_custom:
DEFINE_OP(op_get_by_id)
DEFINE_OP(op_get_by_id_with_this)
DEFINE_OP(op_get_by_val)
@@ -435,6 +437,8 @@
case op_get_array_length:
case op_get_by_id_proto_load:
case op_get_by_id_unset:
+ case op_get_by_id_proto_accessor:
+ case op_get_by_id_proto_custom:
DEFINE_SLOWCASE_OP(op_get_by_id)
DEFINE_SLOWCASE_OP(op_get_by_val)
DEFINE_SLOWCASE_OP(op_instanceof)
Modified: trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp (202626 => 202627)
--- trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp 2016-06-29 16:50:21 UTC (rev 202626)
+++ trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp 2016-06-29 16:53:25 UTC (rev 202627)
@@ -598,6 +598,8 @@
ObjectPropertyConditionSet conditions;
if (slot.isUnset())
conditions = generateConditionsForPropertyMiss(vm, codeBlock, exec, structure, ident.impl());
+ else if (slot.isCustom())
+ conditions = generateConditionsForPrototypePropertyHitCustom(vm, codeBlock, exec, structure, slot.slotBase(), ident.impl());
else
conditions = generateConditionsForPrototypePropertyHit(vm, codeBlock, exec, structure, slot.slotBase(), ident.impl());
@@ -614,7 +616,7 @@
offset = condition.condition().offset();
result.iterator->value.add(condition, pc)->install();
}
- ASSERT((offset == invalidOffset) == slot.isUnset());
+ ASSERT((offset == invalidOffset) == (slot.isUnset() || slot.isCustom()));
ConcurrentJITLocker locker(codeBlock->m_lock);
@@ -622,10 +624,20 @@
pc[0].u.opcode = LLInt::getOpcode(op_get_by_id_unset);
pc[4].u.structureID = structure->id();
return;
+ } else if (slot.isCustom()) {
+ pc[0].u.opcode = LLInt::getOpcode(op_get_by_id_proto_custom);
+ pc[4].u.structureID = structure->id();
+ pc[5].u.getterFunc = slot.customGetter();
+ pc[6].u.pointer = slot.attributes() & CustomAccessor ? 0 : slot.slotBase();
+ return;
}
- ASSERT(slot.isValue());
+ ASSERT(slot.isValue() || slot.isAccessor());
- pc[0].u.opcode = LLInt::getOpcode(op_get_by_id_proto_load);
+ if (slot.isAccessor())
+ pc[0].u.opcode = LLInt::getOpcode(op_get_by_id_proto_accessor);
+ else
+ pc[0].u.opcode = LLInt::getOpcode(op_get_by_id_proto_load);
+
pc[4].u.structureID = structure->id();
pc[5].u.operand = offset;
// We know that this pointer will remain valid because it will be cleared by either a watchpoint fire or
@@ -666,10 +678,12 @@
ConcurrentJITLocker locker(codeBlock->m_lock);
- pc[4].u.structureID = structure->id();
- pc[5].u.operand = slot.cachedOffset();
+ if (slot.isValue()) {
+ pc[4].u.structureID = structure->id();
+ pc[5].u.operand = slot.cachedOffset();
+ }
}
- } else if (UNLIKELY(pc[7].u.operand && (slot.isValue() || slot.isUnset()))) {
+ } else if (UNLIKELY(pc[7].u.operand && (slot.isValue() || slot.isUnset() || ((slot.isAccessor() || slot.isCustom()) && (slot.slotBase() != baseValue))))) {
ASSERT(slot.slotBase() != baseValue);
if (!(--pc[7].u.operand))
@@ -691,6 +705,19 @@
LLINT_END();
}
+LLINT_SLOW_PATH_DECL(slow_path_get_proto_accessor)
+{
+ LLINT_BEGIN();
+ JSValue baseValue = LLINT_OP_C(2).jsValue();
+ PropertyOffset offset = pc[5].u.operand;
+ JSObject* slotBase = jsCast<JSObject*>(pc[6].u.jsCell.get());
+ JSValue getterSetter = slotBase->getDirect(offset);
+
+ JSValue result = callGetter(exec, baseValue, getterSetter);
+
+ LLINT_RETURN_PROFILED(op_get_by_id, result);
+}
+
LLINT_SLOW_PATH_DECL(slow_path_get_arguments_length)
{
LLINT_BEGIN();
Modified: trunk/Source/_javascript_Core/llint/LLIntSlowPaths.h (202626 => 202627)
--- trunk/Source/_javascript_Core/llint/LLIntSlowPaths.h 2016-06-29 16:50:21 UTC (rev 202626)
+++ trunk/Source/_javascript_Core/llint/LLIntSlowPaths.h 2016-06-29 16:53:25 UTC (rev 202627)
@@ -73,6 +73,7 @@
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_instanceof_custom);
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_try_get_by_id);
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_by_id);
+LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_proto_accessor);
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_arguments_length);
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_put_by_id);
LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_del_by_id);
Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm (202626 => 202627)
--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm 2016-06-29 16:50:21 UTC (rev 202626)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm 2016-06-29 16:53:25 UTC (rev 202627)
@@ -423,6 +423,16 @@
end
end
+macro loadIdentifier(index, dest)
+ loadp CodeBlock[cfr], t1
+ loadp CodeBlock::m_unlinkedCode[t1], t2
+ loadp UnlinkedCodeBlock::m_identifiers[t2], t1
+ move index, t2
+ mulp sizeof Identifier, t2
+ addp t2, t1
+ loadp Identifier::m_string[t1], dest
+end
+
macro checkStackPointerAlignment(tempReg, location)
if ARM64 or C_LOOP or SH4
# ARM64 will check for us!
Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm (202626 => 202627)
--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm 2016-06-29 16:50:21 UTC (rev 202626)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm 2016-06-29 16:53:25 UTC (rev 202627)
@@ -1423,6 +1423,66 @@
dispatch(9)
+_llint_op_get_by_id_proto_accessor:
+ traceExecution()
+ loadi 8[PC], t0
+ loadi 16[PC], t1
+ loadConstantOrVariablePayload(t0, CellTag, t3, .opGetByIdProtoAcessorSlow)
+ bineq JSCell::m_structureID[t3], t1, .opGetByIdProtoAcessorSlow
+ callSlowPath(_llint_slow_path_get_proto_accessor)
+ dispatch(9)
+
+.opGetByIdProtoAcessorSlow:
+ callSlowPath(_llint_slow_path_get_by_id)
+ dispatch(9)
+
+macro loadEncodedThisValue(baseValue, dest)
+ loadp 24[PC], dest
+ bineq 0, dest, .loadEncodedThisValueDone
+ move baseValue, dest
+ .loadEncodedThisValueDone:
+end
+
+_llint_op_get_by_id_proto_custom:
+ traceExecution()
+ loadi 8[PC], t0
+ loadi 16[PC], t1
+ loadConstantOrVariablePayload(t0, CellTag, t3, .opGetByIdProtoCustomSlow)
+ bineq JSCell::m_structureID[t3], t1, .opGetByIdProtoCustomSlow
+ # Setting the topCallFrame
+ loadp Callee[cfr], t0
+ andp MarkedBlockMask, t0, t1
+ loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t1], t1
+ storep cfr, VM::topCallFrame[t1]
+ loadi 12[PC], t0
+ loadIdentifier(t0, t2)
+ loadEncodedThisValue(t3, t1)
+ loadp 20[PC], t0
+ # Inlining the GetValueFunc call
+ push t1 # Load arg3 JSObject *
+ push t2 # Load arg2 PropertyName
+ move CellTag, t3
+ if BIG_ENDIAN
+ push t1 # Load arg1 Payload of EncodedJSValue
+ push t3 # Load arg1 Tag of EncodedJSValue
+ else
+ push t3 # Load arg1 Tag of EncodedJSValue
+ push t1 # Load arg1 Payload of EncodedJSValue
+ end
+ push cfr # Loading exec
+ call t0
+ addp 20, sp
+ loadi 4[PC], t2
+ storei r1, TagOffset[cfr, t2, 8]
+ storei r0, PayloadOffset[cfr, t2, 8]
+ valueProfile(r0, r1, 32, t2)
+ dispatch(9)
+
+.opGetByIdProtoCustomSlow:
+ callSlowPath(_llint_slow_path_get_by_id)
+ dispatch(9)
+
+
_llint_op_get_array_length:
traceExecution()
loadi 8[PC], t0
Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm (202626 => 202627)
--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm 2016-06-29 16:50:21 UTC (rev 202626)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm 2016-06-29 16:53:25 UTC (rev 202627)
@@ -1294,6 +1294,63 @@
dispatch(9)
+_llint_op_get_by_id_proto_accessor:
+ traceExecution()
+ loadisFromInstruction(2, t0)
+ loadConstantOrVariableCell(t0, t3, .opGetByIdProtoAcessorSlow)
+ loadi JSCell::m_structureID[t3], t1
+ loadisFromInstruction(4, t2)
+ bineq t2, t1, .opGetByIdProtoAcessorSlow
+ callSlowPath(_llint_slow_path_get_proto_accessor)
+ dispatch(9)
+
+.opGetByIdProtoAcessorSlow:
+ callSlowPath(_llint_slow_path_get_by_id)
+ dispatch(9)
+
+
+macro loadEncodedThisValue(baseValue, dest)
+ loadpFromInstruction(6, dest)
+ bineq 0, dest, .loadEncodedThisValueDone
+ move baseValue, dest
+ .loadEncodedThisValueDone:
+end
+
+_llint_op_get_by_id_proto_custom:
+ traceExecution()
+ loadisFromInstruction(2, t0)
+ loadConstantOrVariableCell(t0, t3, .opGetByIdProtoCustomSlow)
+ loadi JSCell::m_structureID[t3], t1
+ loadisFromInstruction(4, t2)
+ bineq t2, t1, .opGetByIdProtoCustomSlow
+ # Setting the topCallFrame
+ loadp Callee[cfr], t0
+ andp MarkedBlockMask, t0, t1
+ loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t1], t1
+ storep cfr, VM::topCallFrame[t1]
+ push PC
+ push PB
+ loadpFromInstruction(3, t0)
+ loadIdentifier(t0, a2)
+ loadEncodedThisValue(t3, a1)
+ loadpFromInstruction(5, t0)
+ prepareStateForCCall()
+ move cfr, a0
+ move a1, a3
+ cCall4(t0)
+ restoreStateAfterCCall()
+ pop PB
+ pop PC
+ loadisFromInstruction(1, t2)
+ storeq r0, [cfr, t2, 8]
+ valueProfile(r0, 8, t1)
+ dispatch(9)
+
+.opGetByIdProtoCustomSlow:
+ callSlowPath(_llint_slow_path_get_by_id)
+ dispatch(9)
+
+
_llint_op_get_array_length:
traceExecution()
loadisFromInstruction(2, t0)
Modified: trunk/Source/_javascript_Core/runtime/Identifier.h (202626 => 202627)
--- trunk/Source/_javascript_Core/runtime/Identifier.h 2016-06-29 16:50:21 UTC (rev 202626)
+++ trunk/Source/_javascript_Core/runtime/Identifier.h 2016-06-29 16:53:25 UTC (rev 202627)
@@ -87,6 +87,7 @@
class Identifier {
friend class Structure;
+ friend class LLIntOffsetsExtractor;
public:
Identifier() { }
enum EmptyIdentifierFlag { EmptyIdentifier };
Added: trunk/Source/_javascript_Core/tests/stress/llint-get-by-id-proto-accessor.js (0 => 202627)
--- trunk/Source/_javascript_Core/tests/stress/llint-get-by-id-proto-accessor.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/llint-get-by-id-proto-accessor.js 2016-06-29 16:53:25 UTC (rev 202627)
@@ -0,0 +1,18 @@
+foo = {};
+var expected = 6;
+Object.defineProperty(Object.prototype, "bar", { get: () => { return 2 * 3; } });
+
+function test() {
+ if (foo.bar != expected) {
+ throw new Error();
+ }
+}
+
+for (var i = 0; i < 10; i++) {
+ if (i == 9) {
+ foo = {bar: 7};
+ expected = 7;
+ }
+ test();
+}
+
Added: trunk/Source/_javascript_Core/tests/stress/llint-get-by-id-proto-custom.js (0 => 202627)
--- trunk/Source/_javascript_Core/tests/stress/llint-get-by-id-proto-custom.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/llint-get-by-id-proto-custom.js 2016-06-29 16:53:25 UTC (rev 202627)
@@ -0,0 +1,13 @@
+var v = Object.create(createCustomGetterObject());
+var expected = v.customGetter;
+
+for (var i = 0; i < 10; i++) {
+ if (i == 9) {
+ v = {customGetter: 10};
+ expected = 10;
+ }
+ if (v.customGetter != expected) {
+ throw Error("");
+ }
+}
+