Getter and setter on super are called with wrong "this" object
https://bugs.webkit.org/show_bug.cgi?id=147064
<rdar://problem/21885916>

Reviewed by Filip Pizlo.

This patch implements calls to 'super' getters and setters.
The problem before is we were passing the 'super' (i.e, the prototype
object) as the this value to these getters/setters, which is wrong.
We should be passing the caller's this value.

To implement this behavior, I've introduced four new opcodes and their corresponding DFG nodes:
- op_get_by_id_with_this | GetByIdWithThis
- op_put_by_id_with_this | PutByIdWithThis
- op_get_by_val_with_this | GetByValWithThis
- op_put_by_val_with_this | PutByValWithThis

These are implemented with no optimizations. The future plan is
to unite them with the *by_id and *by_val opcodes and nodes:
https://bugs.webkit.org/show_bug.cgi?id=157215

* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitGetById):
(JSC::BytecodeGenerator::emitPutById):
(JSC::BytecodeGenerator::emitDirectPutById):
(JSC::BytecodeGenerator::emitGetByVal):
(JSC::BytecodeGenerator::emitPutByVal):
(JSC::BytecodeGenerator::emitDirectPutByVal):
(JSC::BytecodeGenerator::emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment):
(JSC::BytecodeGenerator::ensureThis):
(JSC::BytecodeGenerator::isThisUsedInInnerArrowFunction):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::ThisNode::emitBytecode):
(JSC::emitHomeObjectForCallee):
(JSC::emitSuperBaseForCallee):
(JSC::emitGetSuperFunctionForConstruct):
(JSC::SuperNode::emitBytecode):
(JSC::NewTargetNode::emitBytecode):
(JSC::TaggedTemplateNode::emitBytecode):
(JSC::BracketAccessorNode::emitBytecode):
(JSC::DotAccessorNode::emitBytecode):
(JSC::FunctionCallValueNode::emitBytecode):
(JSC::FunctionCallBracketNode::emitBytecode):
(JSC::FunctionCallDotNode::emitBytecode):
(JSC::CallFunctionCallDotNode::emitBytecode):
(JSC::ApplyFunctionCallDotNode::emitBytecode):
(JSC::PostfixNode::emitBracket):
(JSC::PostfixNode::emitDot):
(JSC::PrefixNode::emitBracket):
(JSC::PrefixNode::emitDot):
(JSC::AssignDotNode::emitBytecode):
(JSC::ReadModifyDotNode::emitBytecode):
(JSC::AssignBracketNode::emitBytecode):
(JSC::ReadModifyBracketNode::emitBytecode):
(JSC::ForInNode::emitLoopHeader):
(JSC::ForOfNode::emitBytecode):
(JSC::AssignmentElementNode::bindValue):
* 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/DFGNode.h:
(JSC::DFG::Node::hasIdentifier):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
(JSC::DFG::newTypedArrayWithSize):
(JSC::DFG::putWithThis):
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileGetById):
(JSC::FTL::DFG::LowerDFGToB3::compileGetByIdWithThis):
(JSC::FTL::DFG::LowerDFGToB3::compileGetByValWithThis):
(JSC::FTL::DFG::LowerDFGToB3::compilePutByIdWithThis):
(JSC::FTL::DFG::LowerDFGToB3::compilePutByValWithThis):
(JSC::FTL::DFG::LowerDFGToB3::compilePutById):
* jit/CCallHelpers.cpp:
(JSC::CCallHelpers::setupShadowChickenPacket):
(JSC::CCallHelpers::setupFourStubArgsGPR):
* jit/CCallHelpers.h:
(JSC::CCallHelpers::setupArgumentsWithExecState):
(JSC::CCallHelpers::setupThreeStubArgsGPR):
(JSC::CCallHelpers::setupTwoStubArgsFPR):
(JSC::CCallHelpers::setupStubArguments134):
* jit/GPRInfo.h:
(JSC::argumentRegisterFor): Deleted.
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
* jit/JITOperations.h:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::emit_op_put_by_val_with_this):
(JSC::JIT::emitGenericContiguousPutByVal):
(JSC::JIT::emit_op_get_by_id):
(JSC::JIT::emit_op_get_by_id_with_this):
(JSC::JIT::emit_op_get_by_val_with_this):
(JSC::JIT::emitSlow_op_get_by_id):
(JSC::JIT::emit_op_put_by_id):
(JSC::JIT::emit_op_put_by_id_with_this):
(JSC::JIT::emitSlow_op_put_by_id):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_put_to_arguments):
(JSC::JIT::emit_op_get_by_id_with_this):
(JSC::JIT::emit_op_get_by_val_with_this):
(JSC::JIT::emit_op_put_by_id_with_this):
(JSC::JIT::emit_op_put_by_val_with_this):
* llint/LowLevelInterpreter.asm:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/CommonSlowPaths.h:
* tests/stress/super-property-access-exceptions.js: Added.
(assert):
(test):
(test.fooProp):
(test.A.prototype.get foo):
(test.A.prototype.get x):
(test.A):
(test.B):
(test.B.prototype.bar):
(test.B.prototype.baz):
(test.foo):
(test.func):
(test.A.prototype.set foo):
* tests/stress/super-property-access-tdz.js: Added.
(assert):
(test):
(shouldThrowTDZ):
(test.A.prototype.get foo):
(test.A.prototype.set foo):
(test.A):
(test.fooProp):
(test.B):
(test.C):
(test.D):
(test.E):
(test.F):
* tests/stress/super-property-access.js: Added.
(assert):
(test):
(func):
(test.A):
(test.A.prototype.set value):
(test.A.prototype.get value):
(test.B.prototype.set value):
(test.B.prototype.get value):
(test.B):
(test.value):
(test.A.prototype.get func):
(test.B.prototype.inc):
(test.B.prototype.dec):
(test.B.prototype.preInc):
(test.B.prototype.preDec):
(test.B.prototype.plusEq):
(test.B.prototype.minusEq):
(test.B.prototype.timesEq):
(test.B.prototype.divEq):
(test.B.prototype.funcDot):
(test.B.prototype.funcBracket):
(test.foo):
(test.B.prototype.baz):
(test.B.prototype.jaz):
(test.B.prototype.bar):
(test.B.prototype.index):
(test.):
(test.prototype.bar):
(test.A.prototype.set foo):
(test.A.prototype.get array):
(test.A.prototype.get foo):
(test.obj):
(test.A.prototype.get call):
(test.A.prototype.get apply):
(test.B.prototype.foo):
(test.A.prototype.get i):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@200586 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index f974a77..e64d787 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,206 @@
+2016-05-09  Saam barati  <sbarati@apple.com>
+
+        Getter and setter on super are called with wrong "this" object
+        https://bugs.webkit.org/show_bug.cgi?id=147064
+        <rdar://problem/21885916>
+
+        Reviewed by Filip Pizlo.
+
+        This patch implements calls to 'super' getters and setters.
+        The problem before is we were passing the 'super' (i.e, the prototype
+        object) as the this value to these getters/setters, which is wrong. 
+        We should be passing the caller's this value.
+
+        To implement this behavior, I've introduced four new opcodes and their corresponding DFG nodes:
+        - op_get_by_id_with_this | GetByIdWithThis
+        - op_put_by_id_with_this | PutByIdWithThis
+        - op_get_by_val_with_this | GetByValWithThis
+        - op_put_by_val_with_this | PutByValWithThis
+
+        These are implemented with no optimizations. The future plan is 
+        to unite them with the *by_id and *by_val opcodes and nodes:
+        https://bugs.webkit.org/show_bug.cgi?id=157215
+
+        * bytecode/BytecodeList.json:
+        * bytecode/BytecodeUseDef.h:
+        (JSC::computeUsesForBytecodeOffset):
+        (JSC::computeDefsForBytecodeOffset):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpBytecode):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitGetById):
+        (JSC::BytecodeGenerator::emitPutById):
+        (JSC::BytecodeGenerator::emitDirectPutById):
+        (JSC::BytecodeGenerator::emitGetByVal):
+        (JSC::BytecodeGenerator::emitPutByVal):
+        (JSC::BytecodeGenerator::emitDirectPutByVal):
+        (JSC::BytecodeGenerator::emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment):
+        (JSC::BytecodeGenerator::ensureThis):
+        (JSC::BytecodeGenerator::isThisUsedInInnerArrowFunction):
+        * bytecompiler/BytecodeGenerator.h:
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::ThisNode::emitBytecode):
+        (JSC::emitHomeObjectForCallee):
+        (JSC::emitSuperBaseForCallee):
+        (JSC::emitGetSuperFunctionForConstruct):
+        (JSC::SuperNode::emitBytecode):
+        (JSC::NewTargetNode::emitBytecode):
+        (JSC::TaggedTemplateNode::emitBytecode):
+        (JSC::BracketAccessorNode::emitBytecode):
+        (JSC::DotAccessorNode::emitBytecode):
+        (JSC::FunctionCallValueNode::emitBytecode):
+        (JSC::FunctionCallBracketNode::emitBytecode):
+        (JSC::FunctionCallDotNode::emitBytecode):
+        (JSC::CallFunctionCallDotNode::emitBytecode):
+        (JSC::ApplyFunctionCallDotNode::emitBytecode):
+        (JSC::PostfixNode::emitBracket):
+        (JSC::PostfixNode::emitDot):
+        (JSC::PrefixNode::emitBracket):
+        (JSC::PrefixNode::emitDot):
+        (JSC::AssignDotNode::emitBytecode):
+        (JSC::ReadModifyDotNode::emitBytecode):
+        (JSC::AssignBracketNode::emitBytecode):
+        (JSC::ReadModifyBracketNode::emitBytecode):
+        (JSC::ForInNode::emitLoopHeader):
+        (JSC::ForOfNode::emitBytecode):
+        (JSC::AssignmentElementNode::bindValue):
+        * 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/DFGNode.h:
+        (JSC::DFG::Node::hasIdentifier):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        (JSC::DFG::newTypedArrayWithSize):
+        (JSC::DFG::putWithThis):
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::callOperation):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileGetById):
+        (JSC::FTL::DFG::LowerDFGToB3::compileGetByIdWithThis):
+        (JSC::FTL::DFG::LowerDFGToB3::compileGetByValWithThis):
+        (JSC::FTL::DFG::LowerDFGToB3::compilePutByIdWithThis):
+        (JSC::FTL::DFG::LowerDFGToB3::compilePutByValWithThis):
+        (JSC::FTL::DFG::LowerDFGToB3::compilePutById):
+        * jit/CCallHelpers.cpp:
+        (JSC::CCallHelpers::setupShadowChickenPacket):
+        (JSC::CCallHelpers::setupFourStubArgsGPR):
+        * jit/CCallHelpers.h:
+        (JSC::CCallHelpers::setupArgumentsWithExecState):
+        (JSC::CCallHelpers::setupThreeStubArgsGPR):
+        (JSC::CCallHelpers::setupTwoStubArgsFPR):
+        (JSC::CCallHelpers::setupStubArguments134):
+        * jit/GPRInfo.h:
+        (JSC::argumentRegisterFor): Deleted.
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        * jit/JIT.h:
+        * jit/JITOperations.h:
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emit_op_put_by_val):
+        (JSC::JIT::emit_op_put_by_val_with_this):
+        (JSC::JIT::emitGenericContiguousPutByVal):
+        (JSC::JIT::emit_op_get_by_id):
+        (JSC::JIT::emit_op_get_by_id_with_this):
+        (JSC::JIT::emit_op_get_by_val_with_this):
+        (JSC::JIT::emitSlow_op_get_by_id):
+        (JSC::JIT::emit_op_put_by_id):
+        (JSC::JIT::emit_op_put_by_id_with_this):
+        (JSC::JIT::emitSlow_op_put_by_id):
+        * jit/JITPropertyAccess32_64.cpp:
+        (JSC::JIT::emit_op_put_to_arguments):
+        (JSC::JIT::emit_op_get_by_id_with_this):
+        (JSC::JIT::emit_op_get_by_val_with_this):
+        (JSC::JIT::emit_op_put_by_id_with_this):
+        (JSC::JIT::emit_op_put_by_val_with_this):
+        * llint/LowLevelInterpreter.asm:
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+        * runtime/CommonSlowPaths.h:
+        * tests/stress/super-property-access-exceptions.js: Added.
+        (assert):
+        (test):
+        (test.fooProp):
+        (test.A.prototype.get foo):
+        (test.A.prototype.get x):
+        (test.A):
+        (test.B):
+        (test.B.prototype.bar):
+        (test.B.prototype.baz):
+        (test.foo):
+        (test.func):
+        (test.A.prototype.set foo):
+        * tests/stress/super-property-access-tdz.js: Added.
+        (assert):
+        (test):
+        (shouldThrowTDZ):
+        (test.A.prototype.get foo):
+        (test.A.prototype.set foo):
+        (test.A):
+        (test.fooProp):
+        (test.B):
+        (test.C):
+        (test.D):
+        (test.E):
+        (test.F):
+        * tests/stress/super-property-access.js: Added.
+        (assert):
+        (test):
+        (func):
+        (test.A):
+        (test.A.prototype.set value):
+        (test.A.prototype.get value):
+        (test.B.prototype.set value):
+        (test.B.prototype.get value):
+        (test.B):
+        (test.value):
+        (test.A.prototype.get func):
+        (test.B.prototype.inc):
+        (test.B.prototype.dec):
+        (test.B.prototype.preInc):
+        (test.B.prototype.preDec):
+        (test.B.prototype.plusEq):
+        (test.B.prototype.minusEq):
+        (test.B.prototype.timesEq):
+        (test.B.prototype.divEq):
+        (test.B.prototype.funcDot):
+        (test.B.prototype.funcBracket):
+        (test.foo):
+        (test.B.prototype.baz):
+        (test.B.prototype.jaz):
+        (test.B.prototype.bar):
+        (test.B.prototype.index):
+        (test.):
+        (test.prototype.bar):
+        (test.A.prototype.set foo):
+        (test.A.prototype.get array):
+        (test.A.prototype.get foo):
+        (test.obj):
+        (test.A.prototype.get call):
+        (test.A.prototype.get apply):
+        (test.B.prototype.foo):
+        (test.A.prototype.get i):
+
 2016-05-08  Chris Dumez  <cdumez@apple.com>
 
         [COCOA] Disable HAVE_DTRACE at build time
diff --git a/Source/JavaScriptCore/bytecode/BytecodeList.json b/Source/JavaScriptCore/bytecode/BytecodeList.json
index 6723c92..7b49c64 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeList.json
+++ b/Source/JavaScriptCore/bytecode/BytecodeList.json
@@ -60,11 +60,15 @@
             { "name" : "op_in", "length" : 4 },
             { "name" : "op_try_get_by_id", "length" : 4 },
             { "name" : "op_get_by_id", "length" : 9  },
+            { "name" : "op_get_by_id_with_this", "length" : 5 },
+            { "name" : "op_get_by_val_with_this", "length" : 5 },
             { "name" : "op_get_array_length", "length" : 9 },
             { "name" : "op_put_by_id", "length" : 9 },
+            { "name" : "op_put_by_id_with_this", "length" : 5 },
             { "name" : "op_del_by_id", "length" : 4 },
             { "name" : "op_get_by_val", "length" : 6 },
             { "name" : "op_put_by_val", "length" : 5 },
+            { "name" : "op_put_by_val_with_this", "length" : 5 },
             { "name" : "op_put_by_val_direct", "length" : 5 },
             { "name" : "op_del_by_val", "length" : 4 },
             { "name" : "op_put_by_index", "length" : 4 },
diff --git a/Source/JavaScriptCore/bytecode/BytecodeUseDef.h b/Source/JavaScriptCore/bytecode/BytecodeUseDef.h
index fb05608..4a1672e 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeUseDef.h
+++ b/Source/JavaScriptCore/bytecode/BytecodeUseDef.h
@@ -111,6 +111,21 @@
         functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
         return;
     }
+    case op_put_by_id_with_this: {
+        ASSERT(opcodeLengths[opcodeID] > 4);
+        functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[4].u.operand);
+        return;
+    }
+    case op_put_by_val_with_this: {
+        ASSERT(opcodeLengths[opcodeID] > 4);
+        functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[4].u.operand);
+        return;
+    }
     case op_put_getter_by_id:
     case op_put_setter_by_id: {
         ASSERT(opcodeLengths[opcodeID] > 4);
@@ -203,12 +218,20 @@
     case op_neq:
     case op_eq:
     case op_push_with_scope:
+    case op_get_by_id_with_this:
     case op_del_by_val: {
         ASSERT(opcodeLengths[opcodeID] > 3);
         functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
         functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
         return;
     }
+    case op_get_by_val_with_this: {
+        ASSERT(opcodeLengths[opcodeID] > 4);
+        functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
+        functor(codeBlock, instruction, opcodeID, instruction[4].u.operand);
+        return;
+    }
     case op_instanceof_custom:
     case op_has_structure_property:
     case op_construct_varargs:
@@ -316,6 +339,8 @@
     case op_switch_char:
     case op_switch_string:
     case op_put_by_id:
+    case op_put_by_id_with_this:
+    case op_put_by_val_with_this:
     case op_put_getter_by_id:
     case op_put_setter_by_id:
     case op_put_getter_setter_by_id:
@@ -371,6 +396,8 @@
     case op_construct:
     case op_try_get_by_id:
     case op_get_by_id:
+    case op_get_by_id_with_this:
+    case op_get_by_val_with_this:
     case op_get_array_length:
     case op_overrides_has_instance:
     case op_instanceof:
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index 63e7334..d39c30c 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -1117,11 +1117,47 @@
             dumpValueProfiling(out, it, hasPrintedProfiling);
             break;
         }
+        case op_get_by_id_with_this: {
+            printLocationAndOp(out, exec, location, it, "get_by_id_with_this");
+            int r0 = (++it)->u.operand;
+            int r1 = (++it)->u.operand;
+            int r2 = (++it)->u.operand;
+            int id0 = (++it)->u.operand;
+            out.printf("%s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), idName(id0, identifier(id0)).data());
+            break;
+        }
+        case op_get_by_val_with_this: {
+            int r0 = (++it)->u.operand;
+            int r1 = (++it)->u.operand;
+            int r2 = (++it)->u.operand;
+            int r3 = (++it)->u.operand;
+            printLocationAndOp(out, exec, location, it, "get_by_val_with_this");
+            out.printf("%s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), registerName(r3).data());
+            break;
+        }
         case op_put_by_id: {
             printPutByIdOp(out, exec, location, it, "put_by_id");
             printPutByIdCacheStatus(out, location, stubInfos);
             break;
         }
+        case op_put_by_id_with_this: {
+            int r0 = (++it)->u.operand;
+            int r1 = (++it)->u.operand;
+            int id0 = (++it)->u.operand;
+            int r2 = (++it)->u.operand;
+            printLocationAndOp(out, exec, location, it, "put_by_id_with_this");
+            out.printf("%s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), idName(id0, identifier(id0)).data(), registerName(r2).data());
+            break;
+        }
+        case op_put_by_val_with_this: {
+            int r0 = (++it)->u.operand;
+            int r1 = (++it)->u.operand;
+            int r2 = (++it)->u.operand;
+            int r3 = (++it)->u.operand;
+            printLocationAndOp(out, exec, location, it, "put_by_val_with_this");
+            out.printf("%s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), registerName(r3).data());
+            break;
+        }
         case op_put_getter_by_id: {
             int r0 = (++it)->u.operand;
             int id0 = (++it)->u.operand;
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index 8b3a6aa..c9f80af 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -2410,6 +2410,18 @@
     return dst;
 }
 
+RegisterID* BytecodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, RegisterID* thisVal, const Identifier& property)
+{
+    ASSERT_WITH_MESSAGE(!parseIndex(property), "Indexed properties should be handled with get_by_val.");
+
+    emitOpcode(op_get_by_id_with_this);
+    instructions().append(kill(dst));
+    instructions().append(base->index());
+    instructions().append(thisVal->index());
+    instructions().append(addConstant(property));
+    return dst;
+}
+
 RegisterID* BytecodeGenerator::emitPutById(RegisterID* base, const Identifier& property, RegisterID* value)
 {
     ASSERT_WITH_MESSAGE(!parseIndex(property), "Indexed properties should be handled with put_by_val.");
@@ -2433,6 +2445,21 @@
     return value;
 }
 
+RegisterID* BytecodeGenerator::emitPutById(RegisterID* base, RegisterID* thisValue, const Identifier& property, RegisterID* value)
+{
+    ASSERT_WITH_MESSAGE(!parseIndex(property), "Indexed properties should be handled with put_by_val.");
+
+    unsigned propertyIndex = addConstant(property);
+
+    emitOpcode(op_put_by_id_with_this);
+    instructions().append(base->index());
+    instructions().append(thisValue->index());
+    instructions().append(propertyIndex);
+    instructions().append(value->index());
+
+    return value;
+}
+
 RegisterID* BytecodeGenerator::emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value, PropertyNode::PutType putType)
 {
     ASSERT_WITH_MESSAGE(!parseIndex(property), "Indexed properties should be handled with put_by_val(direct).");
@@ -2557,6 +2584,16 @@
     return dst;
 }
 
+RegisterID* BytecodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* thisValue, RegisterID* property)
+{
+    emitOpcode(op_get_by_val_with_this);
+    instructions().append(kill(dst));
+    instructions().append(base->index());
+    instructions().append(thisValue->index());
+    instructions().append(property->index());
+    return dst;
+}
+
 RegisterID* BytecodeGenerator::emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value)
 {
     UnlinkedArrayProfile arrayProfile = newArrayProfile();
@@ -2569,6 +2606,17 @@
     return value;
 }
 
+RegisterID* BytecodeGenerator::emitPutByVal(RegisterID* base, RegisterID* thisValue, RegisterID* property, RegisterID* value)
+{
+    emitOpcode(op_put_by_val_with_this);
+    instructions().append(base->index());
+    instructions().append(thisValue->index());
+    instructions().append(property->index());
+    instructions().append(value->index());
+
+    return value;
+}
+
 RegisterID* BytecodeGenerator::emitDirectPutByVal(RegisterID* base, RegisterID* property, RegisterID* value)
 {
     UnlinkedArrayProfile arrayProfile = newArrayProfile();
@@ -4215,6 +4263,17 @@
     Variable protoScopeVar = variable(propertyNames().derivedConstructorPrivateName);
     return emitGetFromScope(newTemporary(), emitLoadArrowFunctionLexicalEnvironment(propertyNames().derivedConstructorPrivateName), protoScopeVar, ThrowIfNotFound);
 }
+
+RegisterID* BytecodeGenerator::ensureThis()
+{
+    if (constructorKind() == ConstructorKind::Derived && needsToUpdateArrowFunctionContext() && isSuperCallUsedInInnerArrowFunction())
+        emitLoadThisFromArrowFunctionLexicalEnvironment();
+
+    if (constructorKind() == ConstructorKind::Derived || isDerivedConstructorContext())
+        emitTDZCheck(thisRegister());
+
+    return thisRegister();
+}
     
 bool BytecodeGenerator::isThisUsedInInnerArrowFunction()
 {
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index 0961e02..99bc797 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -502,6 +502,7 @@
         void emitProfileControlFlow(int);
         
         RegisterID* emitLoadArrowFunctionLexicalEnvironment(const Identifier&);
+        RegisterID* ensureThis();
         void emitLoadThisFromArrowFunctionLexicalEnvironment();
         RegisterID* emitLoadNewTargetFromArrowFunctionLexicalEnvironment();
 
@@ -550,12 +551,16 @@
 
         RegisterID* emitTryGetById(RegisterID* dst, RegisterID* base, const Identifier& property);
         RegisterID* emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property);
+        RegisterID* emitGetById(RegisterID* dst, RegisterID* base, RegisterID* thisVal, const Identifier& property);
         RegisterID* emitPutById(RegisterID* base, const Identifier& property, RegisterID* value);
+        RegisterID* emitPutById(RegisterID* base, RegisterID* thisValue, const Identifier& property, RegisterID* value);
         RegisterID* emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value, PropertyNode::PutType);
         RegisterID* emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier&);
         RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
+        RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* thisValue, RegisterID* property);
         RegisterID* emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
         RegisterID* emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value);
+        RegisterID* emitPutByVal(RegisterID* base, RegisterID* thisValue, 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);
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index e1f5ca2..f2530ee 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -145,12 +145,8 @@
 
 RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
-    if (generator.constructorKind() == ConstructorKind::Derived && generator.needsToUpdateArrowFunctionContext() && generator.isSuperCallUsedInInnerArrowFunction())
-        generator.emitLoadThisFromArrowFunctionLexicalEnvironment();
-
-    if (m_shouldAlwaysEmitTDZCheck || generator.constructorKind() == ConstructorKind::Derived || generator.isDerivedConstructorContext())
-        generator.emitTDZCheck(generator.thisRegister());
-
+    generator.ensureThis();
+    UNUSED_PARAM(m_shouldAlwaysEmitTDZCheck);
     if (dst == generator.ignoredResult())
         return 0;
 
@@ -162,19 +158,6 @@
 
 // ------------------------------ SuperNode -------------------------------------
 
-RegisterID* SuperNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
-{
-    if (dst == generator.ignoredResult())
-        return 0;
-
-    if (generator.isDerivedConstructorContext())
-        return generator.emitGetById(generator.finalDestination(dst), generator.emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment(), generator.propertyNames().underscoreProto);
-
-    RegisterID callee;
-    callee.setIndex(JSStack::Callee);
-    return generator.emitGetById(generator.finalDestination(dst), &callee, generator.propertyNames().underscoreProto);
-}
-
 static RegisterID* emitHomeObjectForCallee(BytecodeGenerator& generator)
 {
     if (generator.isDerivedClassContext() || generator.isDerivedConstructorContext()) {
@@ -193,6 +176,22 @@
     return generator.emitGetById(generator.newTemporary(), homeObject.get(), generator.propertyNames().underscoreProto);
 }
 
+static RegisterID* emitGetSuperFunctionForConstruct(BytecodeGenerator& generator)
+{
+    if (generator.isDerivedConstructorContext())
+        return generator.emitGetById(generator.newTemporary(), generator.emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment(), generator.propertyNames().underscoreProto);
+
+    RegisterID callee;
+    callee.setIndex(JSStack::Callee);
+    return generator.emitGetById(generator.newTemporary(), &callee, generator.propertyNames().underscoreProto);
+}
+
+RegisterID* SuperNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+{
+    RegisterID* result = emitSuperBaseForCallee(generator);
+    return generator.moveToDestinationIfNeeded(generator.finalDestination(dst), result);
+}
+
 // ------------------------------ NewTargetNode ----------------------------------
 
 RegisterID* NewTargetNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
@@ -309,13 +308,21 @@
         base = generator.newTemporary();
         base = generator.emitNode(base.get(), bracket->base());
         RefPtr<RegisterID> property = generator.emitNode(bracket->subscript());
-        tag = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get());
+        if (bracket->base()->isSuperNode()) {
+            RefPtr<RegisterID> thisValue = generator.ensureThis();
+            tag = generator.emitGetByVal(generator.newTemporary(), base.get(), thisValue.get(), property.get());
+        } else
+            tag = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get());
     } else {
         ASSERT(m_tag->isDotAccessorNode());
         DotAccessorNode* dot = static_cast<DotAccessorNode*>(m_tag);
         base = generator.newTemporary();
         base = generator.emitNode(base.get(), dot->base());
-        tag = generator.emitGetById(generator.newTemporary(), base.get(), dot->identifier());
+        if (dot->base()->isSuperNode()) {
+            RefPtr<RegisterID> thisValue = generator.ensureThis();
+            tag = generator.emitGetById(generator.newTemporary(), base.get(), thisValue.get(), dot->identifier());
+        } else
+            tag = generator.emitGetById(generator.newTemporary(), base.get(), dot->identifier());
     }
 
     RefPtr<RegisterID> templateObject = generator.emitGetTemplateObject(generator.newTemporary(), this);
@@ -620,29 +627,37 @@
 RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
     if (m_base->isSuperNode()) {
-        // FIXME: Should we generate the profiler info?
+        RefPtr<RegisterID> finalDest = generator.finalDestination(dst);
+        RefPtr<RegisterID> thisValue = generator.ensureThis();
+        RefPtr<RegisterID> superBase = emitSuperBaseForCallee(generator);
         if (isNonIndexStringElement(*m_subscript)) {
             const Identifier& id = static_cast<StringNode*>(m_subscript)->value();
-            return generator.emitGetById(generator.finalDestination(dst), emitSuperBaseForCallee(generator), id);
+            generator.emitGetById(finalDest.get(), superBase.get(), thisValue.get(), id);
+        } else  {
+            RefPtr<RegisterID> subscript = generator.emitNode(m_subscript);
+            generator.emitGetByVal(finalDest.get(), superBase.get(), thisValue.get(), subscript.get());
         }
-        return generator.emitGetByVal(generator.finalDestination(dst), emitSuperBaseForCallee(generator), generator.emitNode(m_subscript));
+
+        generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
+        generator.emitProfileType(finalDest.get(), divotStart(), divotEnd());
+        return finalDest.get();
     }
 
     RegisterID* ret;
-    RegisterID* finalDest = generator.finalDestination(dst);
+    RefPtr<RegisterID> finalDest = generator.finalDestination(dst);
 
     if (isNonIndexStringElement(*m_subscript)) {
         RefPtr<RegisterID> base = generator.emitNode(m_base);
-        ret = generator.emitGetById(finalDest, base.get(), static_cast<StringNode*>(m_subscript)->value());
+        ret = generator.emitGetById(finalDest.get(), base.get(), static_cast<StringNode*>(m_subscript)->value());
     } else {
         RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator));
         RegisterID* property = generator.emitNode(m_subscript);
-        ret = generator.emitGetByVal(finalDest, base.get(), property);
+        ret = generator.emitGetByVal(finalDest.get(), base.get(), property);
     }
 
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
 
-    generator.emitProfileType(finalDest, divotStart(), divotEnd());
+    generator.emitProfileType(finalDest.get(), divotStart(), divotEnd());
     return ret;
 }
 
@@ -650,10 +665,16 @@
 
 RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
-    RefPtr<RegisterID> base = m_base->isSuperNode() ? emitSuperBaseForCallee(generator) : generator.emitNode(m_base);
+    bool baseIsSuper = m_base->isSuperNode();
+    RefPtr<RegisterID> base = baseIsSuper ? emitSuperBaseForCallee(generator) : generator.emitNode(m_base);
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
     RegisterID* finalDest = generator.finalDestination(dst);
-    RegisterID* ret = generator.emitGetById(finalDest, base.get(), m_ident);
+    RegisterID* ret;
+    if (baseIsSuper) {
+        RefPtr<RegisterID> thisValue = generator.ensureThis();
+        ret = generator.emitGetById(finalDest, base.get(), thisValue.get(), m_ident);
+    } else
+        ret = generator.emitGetById(finalDest, base.get(), m_ident);
     generator.emitProfileType(finalDest, divotStart(), divotEnd());
     return ret;
 }
@@ -755,10 +776,11 @@
 
 RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
-    RefPtr<RegisterID> func = generator.emitNode(m_expr);
-    RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get());
-    CallArguments callArguments(generator, m_args);
     if (m_expr->isSuperNode()) {
+        RefPtr<RegisterID> func = emitGetSuperFunctionForConstruct(generator);
+        RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get());
+        CallArguments callArguments(generator, m_args);
+
         ASSERT(generator.isConstructor() || generator.derivedContextType() == DerivedContextType::DerivedConstructorContext);
         ASSERT(generator.constructorKind() == ConstructorKind::Derived || generator.derivedContextType() == DerivedContextType::DerivedConstructorContext);
         generator.emitMove(callArguments.thisRegister(), generator.newTarget());
@@ -782,6 +804,9 @@
         
         return ret;
     }
+    RefPtr<RegisterID> func = generator.emitNode(m_expr);
+    RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get());
+    CallArguments callArguments(generator, m_args);
     generator.emitLoad(callArguments.thisRegister(), jsUndefined());
     RegisterID* ret = generator.emitCallInTailPosition(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd());
     generator.emitProfileType(returnValue.get(), divotStart(), divotEnd());
@@ -922,20 +947,31 @@
     }
 
     RefPtr<RegisterID> function;
+    RefPtr<RegisterID> thisRegister;
+    if (baseIsSuper) {
+        // Note that we only need to do this once because we either have a non-TDZ this or we throw. Once we have a non-TDZ this, we can't change its value back to TDZ.
+        thisRegister = generator.ensureThis();
+    }
     if (subscriptIsNonIndexString) {
         generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd());
-        function = generator.emitGetById(generator.tempDestination(dst), base.get(), static_cast<StringNode*>(m_subscript)->value());
+        if (baseIsSuper)
+            function = generator.emitGetById(generator.tempDestination(dst), base.get(), thisRegister.get(), static_cast<StringNode*>(m_subscript)->value());
+        else
+            function = generator.emitGetById(generator.tempDestination(dst), base.get(), static_cast<StringNode*>(m_subscript)->value());
     } else {
         RefPtr<RegisterID> property = generator.emitNode(m_subscript);
         generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd());
-        function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get());
+        if (baseIsSuper)
+            function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), thisRegister.get(), property.get());
+        else
+            function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get());
     }
 
     RefPtr<RegisterID> returnValue = generator.finalDestination(dst, function.get());
     CallArguments callArguments(generator, m_args);
     if (baseIsSuper) {
         generator.emitTDZCheck(generator.thisRegister());
-        generator.emitMove(callArguments.thisRegister(), generator.thisRegister());
+        generator.emitMove(callArguments.thisRegister(), thisRegister.get());
     } else
         generator.emitMove(callArguments.thisRegister(), base.get());
     RegisterID* ret = generator.emitCallInTailPosition(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd());
@@ -951,13 +987,16 @@
     RefPtr<RegisterID> returnValue = generator.finalDestination(dst, function.get());
     CallArguments callArguments(generator, m_args);
     bool baseIsSuper = m_base->isSuperNode();
-    if (baseIsSuper) {
-        generator.emitTDZCheck(generator.thisRegister());
-        generator.emitMove(callArguments.thisRegister(), generator.thisRegister());
-    } else
+    if (baseIsSuper)
+        generator.emitMove(callArguments.thisRegister(), generator.ensureThis());
+    else
         generator.emitNode(callArguments.thisRegister(), m_base);
     generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd());
-    generator.emitGetById(function.get(), baseIsSuper ? emitSuperBaseForCallee(generator) : callArguments.thisRegister(), m_ident);
+    if (baseIsSuper) {
+        RefPtr<RegisterID> superBase = emitSuperBaseForCallee(generator);
+        generator.emitGetById(function.get(), superBase.get(), callArguments.thisRegister(), m_ident);
+    } else
+        generator.emitGetById(function.get(), callArguments.thisRegister(), m_ident);
     RegisterID* ret = generator.emitCallInTailPosition(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd());
     generator.emitProfileType(returnValue.get(), divotStart(), divotEnd());
     return ret;
@@ -972,7 +1011,11 @@
     RefPtr<RegisterID> function;
     bool emitCallCheck = !generator.isBuiltinFunction();
     if (emitCallCheck) {
-        function = generator.emitGetById(generator.tempDestination(dst), base.get(), generator.propertyNames().builtinNames().callPublicName());
+        if (m_base->isSuperNode()) {
+            RefPtr<RegisterID> thisValue = generator.ensureThis();
+            function = generator.emitGetById(generator.tempDestination(dst), base.get(), thisValue.get(), generator.propertyNames().builtinNames().callPublicName());
+        } else
+            function = generator.emitGetById(generator.tempDestination(dst), base.get(), generator.propertyNames().builtinNames().callPublicName());
         generator.emitJumpIfNotFunctionCall(function.get(), realCall.get());
     }
     RefPtr<RegisterID> returnValue = generator.finalDestination(dst);
@@ -1039,7 +1082,11 @@
     RefPtr<RegisterID> returnValue = generator.finalDestination(dst, function.get());
     bool emitCallCheck = !generator.isBuiltinFunction();
     if (emitCallCheck) {
-        function = generator.emitGetById(generator.tempDestination(dst), base.get(), generator.propertyNames().builtinNames().applyPublicName());
+        if (m_base->isSuperNode()) {
+            RefPtr<RegisterID> thisValue = generator.ensureThis();
+            function = generator.emitGetById(generator.tempDestination(dst), base.get(), thisValue.get(), generator.propertyNames().builtinNames().applyPublicName());
+        } else
+            function = generator.emitGetById(generator.tempDestination(dst), base.get(), generator.propertyNames().builtinNames().applyPublicName());
         generator.emitJumpIfNotFunctionApply(function.get(), realCall.get());
     }
     if (mayBeCall) {
@@ -1196,10 +1243,19 @@
     RefPtr<RegisterID> property = generator.emitNode(subscript);
 
     generator.emitExpressionInfo(bracketAccessor->divot(), bracketAccessor->divotStart(), bracketAccessor->divotEnd());
-    RefPtr<RegisterID> value = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get());
+    RefPtr<RegisterID> value;
+    RefPtr<RegisterID> thisValue;
+    if (baseNode->isSuperNode()) {
+        thisValue = generator.ensureThis();
+        value = generator.emitGetByVal(generator.newTemporary(), base.get(), thisValue.get(), property.get());
+    } else
+        value = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get());
     RegisterID* oldValue = emitPostIncOrDec(generator, generator.tempDestination(dst), value.get(), m_operator);
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    generator.emitPutByVal(base.get(), property.get(), value.get());
+    if (baseNode->isSuperNode())
+        generator.emitPutByVal(base.get(), thisValue.get(), property.get(), value.get());
+    else
+        generator.emitPutByVal(base.get(), property.get(), value.get());
     generator.emitProfileType(value.get(), divotStart(), divotEnd());
     return generator.moveToDestinationIfNeeded(dst, oldValue);
 }
@@ -1212,15 +1268,25 @@
     ASSERT(m_expr->isDotAccessorNode());
     DotAccessorNode* dotAccessor = static_cast<DotAccessorNode*>(m_expr);
     ExpressionNode* baseNode = dotAccessor->base();
+    bool baseIsSuper = baseNode->isSuperNode();
     const Identifier& ident = dotAccessor->identifier();
 
     RefPtr<RegisterID> base = generator.emitNode(baseNode);
 
     generator.emitExpressionInfo(dotAccessor->divot(), dotAccessor->divotStart(), dotAccessor->divotEnd());
-    RefPtr<RegisterID> value = generator.emitGetById(generator.newTemporary(), base.get(), ident);
+    RefPtr<RegisterID> value;
+    RefPtr<RegisterID> thisValue;
+    if (baseIsSuper) {
+        thisValue = generator.ensureThis();
+        value = generator.emitGetById(generator.newTemporary(), base.get(), thisValue.get(), ident);
+    } else
+        value = generator.emitGetById(generator.newTemporary(), base.get(), ident);
     RegisterID* oldValue = emitPostIncOrDec(generator, generator.tempDestination(dst), value.get(), m_operator);
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    generator.emitPutById(base.get(), ident, value.get());
+    if (baseIsSuper)
+        generator.emitPutById(base.get(), thisValue.get(), ident, value.get());
+    else
+        generator.emitPutById(base.get(), ident, value.get());
     generator.emitProfileType(value.get(), divotStart(), divotEnd());
     return generator.moveToDestinationIfNeeded(dst, oldValue);
 }
@@ -1393,10 +1459,19 @@
     RefPtr<RegisterID> propDst = generator.tempDestination(dst);
 
     generator.emitExpressionInfo(bracketAccessor->divot(), bracketAccessor->divotStart(), bracketAccessor->divotEnd());
-    RegisterID* value = generator.emitGetByVal(propDst.get(), base.get(), property.get());
+    RegisterID* value;
+    RefPtr<RegisterID> thisValue;
+    if (baseNode->isSuperNode()) {
+        thisValue = generator.ensureThis();
+        value = generator.emitGetByVal(propDst.get(), base.get(), thisValue.get(), property.get());
+    } else
+        value = generator.emitGetByVal(propDst.get(), base.get(), property.get());
     emitIncOrDec(generator, value, m_operator);
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    generator.emitPutByVal(base.get(), property.get(), value);
+    if (baseNode->isSuperNode())
+        generator.emitPutByVal(base.get(), thisValue.get(), property.get(), value);
+    else
+        generator.emitPutByVal(base.get(), property.get(), value);
     generator.emitProfileType(value, divotStart(), divotEnd());
     return generator.moveToDestinationIfNeeded(dst, propDst.get());
 }
@@ -1412,10 +1487,19 @@
     RefPtr<RegisterID> propDst = generator.tempDestination(dst);
 
     generator.emitExpressionInfo(dotAccessor->divot(), dotAccessor->divotStart(), dotAccessor->divotEnd());
-    RegisterID* value = generator.emitGetById(propDst.get(), base.get(), ident);
+    RegisterID* value;
+    RefPtr<RegisterID> thisValue;
+    if (baseNode->isSuperNode()) {
+        thisValue = generator.ensureThis();
+        value = generator.emitGetById(propDst.get(), base.get(), thisValue.get(), ident);
+    } else
+        value = generator.emitGetById(propDst.get(), base.get(), ident);
     emitIncOrDec(generator, value, m_operator);
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    generator.emitPutById(base.get(), ident, value);
+    if (baseNode->isSuperNode())
+        generator.emitPutById(base.get(), thisValue.get(), ident, value);
+    else
+        generator.emitPutById(base.get(), ident, value);
     generator.emitProfileType(value, divotStart(), divotEnd());
     return generator.moveToDestinationIfNeeded(dst, propDst.get());
 }
@@ -2015,10 +2099,14 @@
     RefPtr<RegisterID> value = generator.destinationForAssignResult(dst);
     RefPtr<RegisterID> result = generator.emitNode(value.get(), m_right);
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result.get() : generator.moveToDestinationIfNeeded(generator.tempDestination(result.get()), result.get());
-    generator.emitPutById(base.get(), m_ident, forwardResult);
-    generator.emitProfileType(forwardResult, divotStart(), divotEnd());
-    return generator.moveToDestinationIfNeeded(dst, forwardResult);
+    RefPtr<RegisterID> forwardResult = (dst == generator.ignoredResult()) ? result.get() : generator.moveToDestinationIfNeeded(generator.tempDestination(result.get()), result.get());
+    if (m_base->isSuperNode()) {
+        RefPtr<RegisterID> thisValue = generator.ensureThis();
+        generator.emitPutById(base.get(), thisValue.get(), m_ident, forwardResult.get());
+    } else
+        generator.emitPutById(base.get(), m_ident, forwardResult.get());
+    generator.emitProfileType(forwardResult.get(), divotStart(), divotEnd());
+    return generator.moveToDestinationIfNeeded(dst, forwardResult.get());
 }
 
 // ------------------------------ ReadModifyDotNode -----------------------------------
@@ -2028,11 +2116,21 @@
     RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_rightHasAssignments, m_right->isPure(generator));
 
     generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd());
-    RefPtr<RegisterID> value = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident);
+    RefPtr<RegisterID> value;
+    RefPtr<RegisterID> thisValue;
+    if (m_base->isSuperNode()) {
+        thisValue = generator.ensureThis();
+        value = generator.emitGetById(generator.tempDestination(dst), base.get(), thisValue.get(), m_ident);
+    } else
+        value = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident);
     RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, static_cast<JSC::Operator>(m_operator), OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
 
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    RegisterID* ret = generator.emitPutById(base.get(), m_ident, updatedValue);
+    RegisterID* ret;
+    if (m_base->isSuperNode())
+        ret = generator.emitPutById(base.get(), thisValue.get(), m_ident, updatedValue);
+    else
+        ret = generator.emitPutById(base.get(), m_ident, updatedValue);
     generator.emitProfileType(updatedValue, divotStart(), divotEnd());
     return ret;
 }
@@ -2056,10 +2154,19 @@
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
     RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result.get() : generator.moveToDestinationIfNeeded(generator.tempDestination(result.get()), result.get());
 
-    if (isNonIndexStringElement(*m_subscript))
-        generator.emitPutById(base.get(), static_cast<StringNode*>(m_subscript)->value(), forwardResult);
-    else
-        generator.emitPutByVal(base.get(), property.get(), forwardResult);
+    if (isNonIndexStringElement(*m_subscript)) {
+        if (m_base->isSuperNode()) {
+            RefPtr<RegisterID> thisValue = generator.ensureThis();
+            generator.emitPutById(base.get(), thisValue.get(), static_cast<StringNode*>(m_subscript)->value(), forwardResult);
+        } else
+            generator.emitPutById(base.get(), static_cast<StringNode*>(m_subscript)->value(), forwardResult);
+    } else {
+        if (m_base->isSuperNode()) {
+            RefPtr<RegisterID> thisValue = generator.ensureThis();
+            generator.emitPutByVal(base.get(), thisValue.get(), property.get(), forwardResult);
+        } else
+            generator.emitPutByVal(base.get(), property.get(), forwardResult);
+    }
 
     generator.emitProfileType(forwardResult, divotStart(), divotEnd());
     return generator.moveToDestinationIfNeeded(dst, forwardResult);
@@ -2073,11 +2180,20 @@
     RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript, m_rightHasAssignments, m_right->isPure(generator));
 
     generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd());
-    RefPtr<RegisterID> value = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get());
+    RefPtr<RegisterID> value;
+    RefPtr<RegisterID> thisValue;
+    if (m_base->isSuperNode()) {
+        thisValue = generator.ensureThis();
+        value = generator.emitGetByVal(generator.tempDestination(dst), base.get(), thisValue.get(), property.get());
+    } else
+        value = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get());
     RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, static_cast<JSC::Operator>(m_operator), OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
 
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    generator.emitPutByVal(base.get(), property.get(), updatedValue);
+    if (m_base->isSuperNode())
+        generator.emitPutByVal(base.get(), thisValue.get(), property.get(), updatedValue);
+    else
+        generator.emitPutByVal(base.get(), property.get(), updatedValue);
     generator.emitProfileType(updatedValue, divotStart(), divotEnd());
 
     return updatedValue;
@@ -2409,18 +2525,26 @@
     if (m_lexpr->isDotAccessorNode()) {
         DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr);
         const Identifier& ident = assignNode->identifier();
-        RegisterID* base = generator.emitNode(assignNode->base());
+        RefPtr<RegisterID> base = generator.emitNode(assignNode->base());
         generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
-        generator.emitPutById(base, ident, propertyName);
+        if (assignNode->base()->isSuperNode()) {
+            RefPtr<RegisterID> thisValue = generator.ensureThis();
+            generator.emitPutById(base.get(), thisValue.get(), ident, propertyName);
+        } else
+            generator.emitPutById(base.get(), ident, propertyName);
         generator.emitProfileType(propertyName, assignNode->divotStart(), assignNode->divotEnd());
         return;
     }
     if (m_lexpr->isBracketAccessorNode()) {
         BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr);
         RefPtr<RegisterID> base = generator.emitNode(assignNode->base());
-        RegisterID* subscript = generator.emitNode(assignNode->subscript());
+        RefPtr<RegisterID> subscript = generator.emitNode(assignNode->subscript());
         generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
-        generator.emitPutByVal(base.get(), subscript, propertyName);
+        if (assignNode->base()->isSuperNode()) {
+            RefPtr<RegisterID> thisValue = generator.ensureThis();
+            generator.emitPutByVal(base.get(), thisValue.get(), subscript.get(), propertyName);
+        } else
+            generator.emitPutByVal(base.get(), subscript.get(), propertyName);
         generator.emitProfileType(propertyName, assignNode->divotStart(), assignNode->divotEnd());
         return;
     }
@@ -2631,7 +2755,11 @@
             RefPtr<RegisterID> base = generator.emitNode(assignNode->base());
             
             generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
-            generator.emitPutById(base.get(), ident, value);
+            if (assignNode->base()->isSuperNode()) {
+                RefPtr<RegisterID> thisValue = generator.ensureThis();
+                generator.emitPutById(base.get(), thisValue.get(), ident, value);
+            } else
+                generator.emitPutById(base.get(), ident, value);
             generator.emitProfileType(value, assignNode->divotStart(), assignNode->divotEnd());
         } else if (m_lexpr->isBracketAccessorNode()) {
             BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr);
@@ -2639,7 +2767,11 @@
             RegisterID* subscript = generator.emitNode(assignNode->subscript());
             
             generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
-            generator.emitPutByVal(base.get(), subscript, value);
+            if (assignNode->base()->isSuperNode()) {
+                RefPtr<RegisterID> thisValue = generator.ensureThis();
+                generator.emitPutByVal(base.get(), thisValue.get(), subscript, value);
+            } else
+                generator.emitPutByVal(base.get(), subscript, value);
             generator.emitProfileType(value, assignNode->divotStart(), assignNode->divotEnd());
         } else {
             ASSERT(m_lexpr->isDestructuringNode());
@@ -3696,14 +3828,22 @@
         DotAccessorNode* lhs = static_cast<DotAccessorNode*>(m_assignmentTarget);
         RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(lhs->base(), true, false);
         generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd());
-        generator.emitPutById(base.get(), lhs->identifier(), value);
+        if (lhs->base()->isSuperNode()) {
+            RefPtr<RegisterID> thisValue = generator.ensureThis();
+            generator.emitPutById(base.get(), thisValue.get(), lhs->identifier(), value);
+        } else
+            generator.emitPutById(base.get(), lhs->identifier(), value);
         generator.emitProfileType(value, divotStart(), divotEnd());
     } else if (m_assignmentTarget->isBracketAccessorNode()) {
         BracketAccessorNode* lhs = static_cast<BracketAccessorNode*>(m_assignmentTarget);
         RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(lhs->base(), true, false);
         RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(lhs->subscript(), true, false);
         generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd());
-        generator.emitPutByVal(base.get(), property.get(), value);
+        if (lhs->base()->isSuperNode()) {
+            RefPtr<RegisterID> thisValue = generator.ensureThis();
+            generator.emitPutByVal(base.get(), thisValue.get(), property.get(), value);
+        } else
+            generator.emitPutByVal(base.get(), property.get(), value);
         generator.emitProfileType(value, divotStart(), divotEnd());
     }
 }
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
index 6c1eb96..09091ec 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
@@ -2179,6 +2179,12 @@
         forNode(node).makeHeapTop();
         break;
     }
+
+    case GetByValWithThis:
+    case GetByIdWithThis:
+        clobberWorld(node->origin.semantic, clobberLimit);
+        forNode(node).makeHeapTop();
+        break;
             
     case GetArrayLength: {
         JSArrayBufferView* view = m_graph.tryGetFoldableView(
@@ -2678,6 +2684,11 @@
         break;
     }
 
+    case PutByValWithThis:
+    case PutByIdWithThis:
+        clobberWorld(node->origin.semantic, clobberLimit);
+        break;
+
     case PutGetterById:
     case PutSetterById:
     case PutGetterSetterById:
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index c21afa1..0b41c06 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -4029,6 +4029,16 @@
             NEXT_OPCODE(op_get_by_val);
         }
 
+        case op_get_by_val_with_this: {
+            Node* base = get(VirtualRegister(currentInstruction[2].u.operand));
+            Node* thisValue = get(VirtualRegister(currentInstruction[3].u.operand));
+            Node* property = get(VirtualRegister(currentInstruction[4].u.operand));
+            Node* getByValWithThis = addToGraph(GetByValWithThis, base, thisValue, property);
+            set(VirtualRegister(currentInstruction[1].u.operand), getByValWithThis);
+
+            NEXT_OPCODE(op_get_by_val_with_this);
+        }
+
         case op_put_by_val_direct:
         case op_put_by_val: {
             Node* base = get(VirtualRegister(currentInstruction[1].u.operand));
@@ -4070,6 +4080,21 @@
             NEXT_OPCODE(op_put_by_val);
         }
 
+        case op_put_by_val_with_this: {
+            Node* base = get(VirtualRegister(currentInstruction[1].u.operand));
+            Node* thisValue = get(VirtualRegister(currentInstruction[2].u.operand));
+            Node* property = get(VirtualRegister(currentInstruction[3].u.operand));
+            Node* value = get(VirtualRegister(currentInstruction[4].u.operand));
+
+            addVarArgChild(base);
+            addVarArgChild(thisValue);
+            addVarArgChild(property);
+            addVarArgChild(value);
+            addToGraph(Node::VarArg, PutByValWithThis, OpInfo(0), OpInfo(0));
+
+            NEXT_OPCODE(op_put_by_val_with_this);
+        }
+
         case op_try_get_by_id: {
             Node* base = get(VirtualRegister(currentInstruction[2].u.operand));
             unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand];
@@ -4103,6 +4128,16 @@
 
             NEXT_OPCODE(op_get_by_id);
         }
+        case op_get_by_id_with_this: {
+            Node* base = get(VirtualRegister(currentInstruction[2].u.operand));
+            Node* thisValue = get(VirtualRegister(currentInstruction[3].u.operand));
+            unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[4].u.operand];
+
+            set(VirtualRegister(currentInstruction[1].u.operand),
+                addToGraph(GetByIdWithThis, OpInfo(identifierNumber), base, thisValue));
+
+            NEXT_OPCODE(op_get_by_id_with_this);
+        }
         case op_put_by_id: {
             Node* value = get(VirtualRegister(currentInstruction[3].u.operand));
             Node* base = get(VirtualRegister(currentInstruction[1].u.operand));
@@ -4118,6 +4153,16 @@
             NEXT_OPCODE(op_put_by_id);
         }
 
+        case op_put_by_id_with_this: {
+            Node* base = get(VirtualRegister(currentInstruction[1].u.operand));
+            Node* thisValue = get(VirtualRegister(currentInstruction[2].u.operand));
+            Node* value = get(VirtualRegister(currentInstruction[4].u.operand));
+            unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand];
+
+            addToGraph(PutByIdWithThis, OpInfo(identifierNumber), base, thisValue, value);
+            NEXT_OPCODE(op_put_by_id_with_this);
+        }
+
         case op_put_getter_by_id:
         case op_put_setter_by_id: {
             Node* base = get(VirtualRegister(currentInstruction[1].u.operand));
diff --git a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
index 198f1a8..cc2d474 100644
--- a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
@@ -156,8 +156,12 @@
     case op_put_by_val_direct:
     case op_try_get_by_id:
     case op_get_by_id:
+    case op_get_by_id_with_this:
+    case op_get_by_val_with_this:
     case op_get_array_length:
     case op_put_by_id:
+    case op_put_by_id_with_this:
+    case op_put_by_val_with_this:
     case op_put_getter_by_id:
     case op_put_setter_by_id:
     case op_put_getter_setter_by_id:
diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h
index 387a61d..f637549 100644
--- a/Source/JavaScriptCore/dfg/DFGClobberize.h
+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h
@@ -439,7 +439,11 @@
         
     case GetById:
     case GetByIdFlush:
+    case GetByIdWithThis:
+    case GetByValWithThis:
     case PutById:
+    case PutByIdWithThis:
+    case PutByValWithThis:
     case PutByIdFlush:
     case PutByIdDirect:
     case PutGetterById:
diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
index 997de3b..6cf0d0b 100644
--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
@@ -99,8 +99,11 @@
     case TryGetById:
     case GetById:
     case GetByIdFlush:
+    case GetByIdWithThis:
     case PutById:
     case PutByIdFlush:
+    case PutByIdWithThis:
+    case PutByValWithThis:
     case PutByIdDirect:
     case PutGetterById:
     case PutSetterById:
@@ -203,6 +206,7 @@
     case GetGetter:
     case GetSetter:
     case GetByVal:
+    case GetByValWithThis:
     case GetIndexedPropertyStorage:
     case GetArrayLength:
     case ArrayPush:
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index a766839..75ea3b9 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -1147,7 +1147,7 @@
                 fixEdge<CellUse>(node->child1());
             break;
         }
-            
+
         case PutById:
         case PutByIdFlush:
         case PutByIdDirect: {
@@ -1575,6 +1575,12 @@
         case ExitOK:
         case BottomValue:
         case TypeOf:
+        case GetByIdWithThis:
+        case PutByIdWithThis:
+        case PutByValWithThis:
+        case GetByValWithThis:
+            break;
+            
             break;
 #else
         default:
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index 4fb694c..98a7b18 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -862,9 +862,11 @@
         case TryGetById:
         case GetById:
         case GetByIdFlush:
+        case GetByIdWithThis:
         case PutById:
         case PutByIdFlush:
         case PutByIdDirect:
+        case PutByIdWithThis:
         case PutGetterById:
         case PutSetterById:
         case PutGetterSetterById:
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index 1be6738..181c790 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -176,6 +176,7 @@
     /* 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) \
+    macro(GetByValWithThis, NodeResultJS | NodeMustGenerate) \
     macro(GetMyArgumentByVal, NodeResultJS | NodeMustGenerate) \
     macro(GetMyArgumentByValOutOfBounds, NodeResultJS | NodeMustGenerate) \
     macro(LoadVarargs, NodeMustGenerate) \
@@ -186,9 +187,12 @@
     macro(TryGetById, NodeResultJS) \
     macro(GetById, NodeResultJS | NodeMustGenerate) \
     macro(GetByIdFlush, NodeResultJS | NodeMustGenerate) \
+    macro(GetByIdWithThis, NodeResultJS | NodeMustGenerate) \
     macro(PutById, NodeMustGenerate) \
     macro(PutByIdFlush, NodeMustGenerate) \
     macro(PutByIdDirect, NodeMustGenerate) \
+    macro(PutByIdWithThis, NodeMustGenerate) \
+    macro(PutByValWithThis, NodeMustGenerate | NodeHasVarArgs) \
     macro(PutGetterById, NodeMustGenerate) \
     macro(PutSetterById, NodeMustGenerate) \
     macro(PutGetterSetterById, NodeMustGenerate) \
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index adb18bc..ce4c283 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -144,6 +144,16 @@
     return bitwise_cast<char*>(ViewClass::create(exec, structure, size));
 }
 
+template <bool strict>
+static ALWAYS_INLINE void putWithThis(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedValue, const Identifier& ident)
+{
+    JSValue baseValue = JSValue::decode(encodedBase);
+    JSValue thisVal = JSValue::decode(encodedThis);
+    JSValue putValue = JSValue::decode(encodedValue);
+    PutPropertySlot slot(thisVal, strict);
+    baseValue.putInline(exec, ident, putValue, slot);
+}
+
 extern "C" {
 
 EncodedJSValue JIT_OPERATION operationToThis(ExecState* exec, EncodedJSValue encodedOp)
@@ -773,6 +783,94 @@
     return JSValue::encode(JSValue::decode(value).toPrimitive(exec));
 }
 
+EncodedJSValue JIT_OPERATION operationGetByIdWithThis(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, UniquedStringImpl* impl)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+
+    JSValue baseValue = JSValue::decode(encodedBase);
+    JSValue thisVal = JSValue::decode(encodedThis);
+    PropertySlot slot(thisVal, PropertySlot::PropertySlot::InternalMethodType::Get);
+    JSValue result = baseValue.get(exec, Identifier::fromUid(exec, impl), slot);
+    return JSValue::encode(result);
+}
+
+EncodedJSValue JIT_OPERATION operationGetByValWithThis(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedSubscript)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+
+    JSValue baseValue = JSValue::decode(encodedBase);
+    JSValue thisVal = JSValue::decode(encodedThis);
+    JSValue subscript = JSValue::decode(encodedSubscript);
+
+    if (LIKELY(baseValue.isCell() && subscript.isString())) {
+        Structure& structure = *baseValue.asCell()->structure(vm);
+        if (JSCell::canUseFastGetOwnProperty(structure)) {
+            if (RefPtr<AtomicStringImpl> existingAtomicString = asString(subscript)->toExistingAtomicString(exec)) {
+                if (JSValue result = baseValue.asCell()->fastGetOwnProperty(vm, structure, existingAtomicString.get()))
+                    return JSValue::encode(result);
+            }
+        }
+    }
+    
+    PropertySlot slot(thisVal, PropertySlot::PropertySlot::InternalMethodType::Get);
+    if (subscript.isUInt32()) {
+        uint32_t i = subscript.asUInt32();
+        if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i))
+            return JSValue::encode(asString(baseValue)->getIndex(exec, i));
+        
+        return JSValue::encode(baseValue.get(exec, i, slot));
+    }
+
+    baseValue.requireObjectCoercible(exec);
+    if (vm.exception())
+        return JSValue::encode(JSValue());
+
+    auto property = subscript.toPropertyKey(exec);
+    if (vm.exception())
+        return JSValue::encode(JSValue());
+    return JSValue::encode(baseValue.get(exec, property, slot));
+}
+
+void JIT_OPERATION operationPutByIdWithThisStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedValue, UniquedStringImpl* impl)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+
+    putWithThis<true>(exec, encodedBase, encodedThis, encodedValue, Identifier::fromUid(exec, impl));
+}
+
+void JIT_OPERATION operationPutByIdWithThis(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedValue, UniquedStringImpl* impl)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+
+    putWithThis<false>(exec, encodedBase, encodedThis, encodedValue, Identifier::fromUid(exec, impl));
+}
+
+void JIT_OPERATION operationPutByValWithThisStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+
+    Identifier property = JSValue::decode(encodedSubscript).toPropertyKey(exec);
+    if (vm.exception())
+        return;
+    putWithThis<true>(exec, encodedBase, encodedThis, encodedValue, property);
+}
+
+void JIT_OPERATION operationPutByValWithThis(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+
+    Identifier property = JSValue::decode(encodedSubscript).toPropertyKey(exec);
+    if (vm.exception())
+        return;
+    putWithThis<false>(exec, encodedBase, encodedThis, encodedValue, property);
+}
+
 char* JIT_OPERATION operationNewArray(ExecState* exec, Structure* arrayStructure, void* buffer, size_t size)
 {
     VM* vm = &exec->vm();
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h
index 79262ff..b199dd7 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.h
+++ b/Source/JavaScriptCore/dfg/DFGOperations.h
@@ -61,6 +61,8 @@
 EncodedJSValue JIT_OPERATION operationGetByValArrayInt(ExecState*, JSArray*, int32_t) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetByValStringInt(ExecState*, JSString*, int32_t) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationToPrimitive(ExecState*, EncodedJSValue) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationGetByIdWithThis(ExecState*, EncodedJSValue, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationGetByValWithThis(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
 char* JIT_OPERATION operationNewArray(ExecState*, Structure*, void*, size_t) WTF_INTERNAL;
 char* JIT_OPERATION operationNewArrayBuffer(ExecState*, Structure*, size_t, size_t) WTF_INTERNAL;
 char* JIT_OPERATION operationNewEmptyArray(ExecState*, Structure*) WTF_INTERNAL;
@@ -98,6 +100,10 @@
 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;
+void JIT_OPERATION operationPutByIdWithThis(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
+void JIT_OPERATION operationPutByIdWithThisStrict(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
+void JIT_OPERATION operationPutByValWithThis(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
+void JIT_OPERATION operationPutByValWithThisStrict(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationArrayPush(ExecState*, EncodedJSValue encodedValue, JSArray*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationArrayPushDouble(ExecState*, double value, JSArray*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationArrayPop(ExecState*, JSArray*) WTF_INTERNAL;
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index b14dccb..212dc79 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -661,6 +661,11 @@
             break;
         }
 
+        case GetByValWithThis:
+        case GetByIdWithThis: {
+            setPrediction(SpecBytecodeTop);
+            break;
+        }
         case TryGetById: {
             setPrediction(SpecBytecodeTop);
             break;
@@ -988,6 +993,8 @@
 #ifndef NDEBUG
         // These get ignored because they don't return anything.
         case PutByValDirect:
+        case PutByValWithThis:
+        case PutByIdWithThis:
         case PutByVal:
         case PutClosureVar:
         case PutToArguments:
diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
index a74c878..f9bdeb9 100644
--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
@@ -195,9 +195,13 @@
     case DeleteById:
     case DeleteByVal:
     case GetById:
+    case GetByIdWithThis:
+    case GetByValWithThis:
     case GetByIdFlush:
     case PutById:
     case PutByIdFlush:
+    case PutByIdWithThis:
+    case PutByValWithThis:
     case PutByIdDirect:
     case PutGetterById:
     case PutSetterById:
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 1beb199..da797d7 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -1270,6 +1270,21 @@
 
 
 #if USE(JSVALUE64)
+    JITCompiler::Call callOperation(J_JITOperation_EJJI operation, GPRReg result, GPRReg arg1, GPRReg arg2, UniquedStringImpl* uid)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, TrustedImmPtr(uid));
+        return appendCallSetResult(operation, result);
+    }
+    JITCompiler::Call callOperation(V_JITOperation_EJJJI operation, GPRReg arg1, GPRReg arg2, GPRReg arg3, UniquedStringImpl* uid)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3, TrustedImmPtr(uid));
+        return appendCall(operation);
+    }
+    JITCompiler::Call callOperation(V_JITOperation_EJJJJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3, arg4);
+        return appendCall(operation);
+    }
     JITCompiler::Call callOperation(V_JITOperation_EOJIUi operation, GPRReg arg1, GPRReg arg2, UniquedStringImpl* impl, unsigned value)
     {
         m_jit.setupArgumentsWithExecState(arg1, arg2, TrustedImmPtr(impl), TrustedImm32(value));
@@ -1689,6 +1704,22 @@
 #define SH4_32BIT_DUMMY_ARG
 #endif
 
+    JITCompiler::Call callOperation(J_JITOperation_EJJI operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Tag, GPRReg arg2Payload, UniquedStringImpl* uid)
+    {
+        m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, arg2Payload, arg2Tag, TrustedImmPtr(uid));
+        return appendCallSetResult(operation, resultPayload, resultTag);
+    }
+    JITCompiler::Call callOperation(V_JITOperation_EJJJI operation, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Tag, GPRReg arg2Payload, GPRReg arg3Tag, GPRReg arg3Payload, UniquedStringImpl* uid)
+    {
+        m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, arg2Payload, arg2Tag, arg3Payload, arg3Tag, TrustedImmPtr(uid));
+        return appendCall(operation);
+    }
+    JITCompiler::Call callOperation(V_JITOperation_EJJJJ operation, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Tag, GPRReg arg2Payload, GPRReg arg3Tag, GPRReg arg3Payload, GPRReg arg4Tag, GPRReg arg4Payload)
+    {
+        m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, arg2Payload, arg2Tag, arg3Payload, arg3Tag, arg4Payload, arg4Tag);
+        return appendCall(operation);
+    }
+
     JITCompiler::Call callOperation(V_JITOperation_EOJIUi operation, GPRReg arg1, GPRReg arg2Tag, GPRReg arg2Payload, UniquedStringImpl* impl, unsigned value)
     {
         m_jit.setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag, TrustedImmPtr(impl), TrustedImm32(value));
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 9b07898..d740d77 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -2681,6 +2681,30 @@
         break;
     }
 
+    case GetByValWithThis: {
+        JSValueOperand base(this, node->child1());
+        GPRReg baseTag = base.tagGPR();
+        GPRReg basePayload = base.payloadGPR();
+        JSValueOperand thisValue(this, node->child2());
+        GPRReg thisValueTag = thisValue.tagGPR();
+        GPRReg thisValuePayload = thisValue.payloadGPR();
+        JSValueOperand subscript(this, node->child3());
+        GPRReg subscriptTag = subscript.tagGPR();
+        GPRReg subscriptPayload = subscript.payloadGPR();
+
+        GPRFlushedCallResult resultPayload(this);
+        GPRFlushedCallResult2 resultTag(this);
+        GPRReg resultPayloadGPR = resultPayload.gpr();
+        GPRReg resultTagGPR = resultTag.gpr();
+
+        flushRegisters();
+        callOperation(operationGetByValWithThis, resultTagGPR, resultPayloadGPR, baseTag, basePayload, thisValueTag, thisValuePayload, subscriptTag, subscriptPayload);
+        m_jit.exceptionCheck();
+
+        jsValueResult(resultTagGPR, resultPayloadGPR, node);
+        break;
+    }
+
     case PutByValDirect:
     case PutByVal:
     case PutByValAlias: {
@@ -2859,6 +2883,76 @@
         break;
     }
 
+    case PutByValWithThis: {
+#if CPU(X86)
+        // We don't have enough registers on X86 to do this
+        // without setting up the call frame incrementally.
+        unsigned index = 0;
+        m_jit.poke(GPRInfo::callFrameRegister, index++);
+
+        {
+            JSValueOperand base(this, m_jit.graph().varArgChild(node, 0));
+            GPRReg baseTag = base.tagGPR();
+            GPRReg basePayload = base.payloadGPR();
+
+            JSValueOperand thisValue(this, m_jit.graph().varArgChild(node, 1));
+            GPRReg thisValueTag = thisValue.tagGPR();
+            GPRReg thisValuePayload = thisValue.payloadGPR();
+
+            JSValueOperand property(this, m_jit.graph().varArgChild(node, 2));
+            GPRReg propertyTag = property.tagGPR();
+            GPRReg propertyPayload = property.payloadGPR();
+
+            m_jit.poke(basePayload, index++);
+            m_jit.poke(baseTag, index++);
+
+            m_jit.poke(thisValuePayload, index++);
+            m_jit.poke(thisValueTag, index++);
+
+            m_jit.poke(propertyPayload, index++);
+            m_jit.poke(propertyTag, index++);
+
+            flushRegisters();
+        }
+
+        JSValueOperand value(this, m_jit.graph().varArgChild(node, 3));
+        GPRReg valueTag = value.tagGPR();
+        GPRReg valuePayload = value.payloadGPR();
+        m_jit.poke(valuePayload, index++);
+        m_jit.poke(valueTag, index++);
+
+        flushRegisters();
+        appendCall(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValWithThisStrict : operationPutByValWithThis);
+        m_jit.exceptionCheck();
+#else
+        static_assert(GPRInfo::numberOfRegisters >= 8, "We are assuming we have enough registers to make this call without incrementally setting up the arguments.");
+
+        JSValueOperand base(this, m_jit.graph().varArgChild(node, 0));
+        GPRReg baseTag = base.tagGPR();
+        GPRReg basePayload = base.payloadGPR();
+
+        JSValueOperand thisValue(this, m_jit.graph().varArgChild(node, 1));
+        GPRReg thisValueTag = thisValue.tagGPR();
+        GPRReg thisValuePayload = thisValue.payloadGPR();
+
+        JSValueOperand property(this, m_jit.graph().varArgChild(node, 2));
+        GPRReg propertyTag = property.tagGPR();
+        GPRReg propertyPayload = property.payloadGPR();
+
+        JSValueOperand value(this, m_jit.graph().varArgChild(node, 3));
+        GPRReg valueTag = value.tagGPR();
+        GPRReg valuePayload = value.payloadGPR();
+
+        flushRegisters();
+        callOperation(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValWithThisStrict : operationPutByValWithThis,
+            NoResult, baseTag, basePayload, thisValueTag, thisValuePayload, propertyTag, propertyPayload, valueTag, valuePayload);
+        m_jit.exceptionCheck();
+#endif // CPU(X86)
+
+        noResult(node);
+        break;
+    }
+
     case RegExpExec: {
         SpeculateCellOperand globalObject(this, node->child1());
         GPRReg globalObjectGPR = globalObject.gpr();
@@ -4038,6 +4132,27 @@
         break;
     }
 
+    case GetByIdWithThis: {
+        JSValueOperand base(this, node->child1());
+        GPRReg baseTag = base.tagGPR();
+        GPRReg basePayload = base.payloadGPR();
+        JSValueOperand thisValue(this, node->child2());
+        GPRReg thisTag = thisValue.tagGPR();
+        GPRReg thisPayload = thisValue.payloadGPR();
+
+        GPRFlushedCallResult resultPayload(this);
+        GPRFlushedCallResult2 resultTag(this);
+        GPRReg resultPayloadGPR = resultPayload.gpr();
+        GPRReg resultTagGPR = resultTag.gpr();
+
+        flushRegisters();
+        callOperation(operationGetByIdWithThis, resultTagGPR, resultPayloadGPR, baseTag, basePayload, thisTag, thisPayload, identifierUID(node->identifierNumber()));
+        m_jit.exceptionCheck();
+
+        jsValueResult(resultTagGPR, resultPayloadGPR, node);
+        break;
+    }
+
     case GetByIdFlush: {
         if (!node->prediction()) {
             terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
@@ -4315,6 +4430,26 @@
         break;
     }
 
+    case PutByIdWithThis: {
+        JSValueOperand base(this, node->child1());
+        GPRReg baseTag = base.tagGPR();
+        GPRReg basePayload = base.payloadGPR();
+        JSValueOperand thisValue(this, node->child2());
+        GPRReg thisValueTag = thisValue.tagGPR();
+        GPRReg thisValuePayload = thisValue.payloadGPR();
+        JSValueOperand value(this, node->child3());
+        GPRReg valueTag = value.tagGPR();
+        GPRReg valuePayload = value.payloadGPR();
+
+        flushRegisters();
+        callOperation(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByIdWithThisStrict : operationPutByIdWithThis,
+            NoResult, baseTag, basePayload, thisValueTag, thisValuePayload, valueTag, valuePayload, identifierUID(node->identifierNumber()));
+        m_jit.exceptionCheck();
+
+        noResult(node);
+        break;
+    }
+
     case PutGetterById:
     case PutSetterById: {
         compilePutAccessorById(node);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 16e1778..d3a8ba8 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -2763,6 +2763,25 @@
         break;
     }
 
+    case GetByValWithThis: {
+        JSValueOperand base(this, node->child1());
+        GPRReg baseGPR = base.gpr();
+        JSValueOperand thisValue(this, node->child2());
+        GPRReg thisValueGPR = thisValue.gpr();
+        JSValueOperand subscript(this, node->child3());
+        GPRReg subscriptGPR = subscript.gpr();
+
+        GPRFlushedCallResult result(this);
+        GPRReg resultGPR = result.gpr();
+
+        flushRegisters();
+        callOperation(operationGetByValWithThis, resultGPR, baseGPR, thisValueGPR, subscriptGPR);
+        m_jit.exceptionCheck();
+
+        jsValueResult(resultGPR, node);
+        break;
+    }
+
     case PutByValDirect:
     case PutByVal:
     case PutByValAlias: {
@@ -4135,6 +4154,23 @@
         break;
     }
 
+    case GetByIdWithThis: {
+        JSValueOperand base(this, node->child1());
+        GPRReg baseGPR = base.gpr();
+        JSValueOperand thisValue(this, node->child2());
+        GPRReg thisValueGPR = thisValue.gpr();
+
+        GPRFlushedCallResult result(this);
+        GPRReg resultGPR = result.gpr();
+
+        flushRegisters();
+        callOperation(operationGetByIdWithThis, resultGPR, baseGPR, thisValueGPR, identifierUID(node->identifierNumber()));
+        m_jit.exceptionCheck();
+
+        jsValueResult(resultGPR, node);
+        break;
+    }
+
     case GetArrayLength:
         compileGetArrayLength(node);
         break;
@@ -4319,6 +4355,40 @@
         break;
     }
 
+    case PutByIdWithThis: {
+        JSValueOperand base(this, node->child1());
+        GPRReg baseGPR = base.gpr();
+        JSValueOperand thisValue(this, node->child2());
+        GPRReg thisValueGPR = thisValue.gpr();
+        JSValueOperand value(this, node->child3());
+        GPRReg valueGPR = value.gpr();
+
+        flushRegisters();
+        callOperation(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByIdWithThisStrict : operationPutByIdWithThis, NoResult, baseGPR, thisValueGPR, valueGPR, identifierUID(node->identifierNumber()));
+        m_jit.exceptionCheck();
+
+        noResult(node);
+        break;
+    }
+
+    case PutByValWithThis: {
+        JSValueOperand base(this, m_jit.graph().varArgChild(node, 0));
+        GPRReg baseGPR = base.gpr();
+        JSValueOperand thisValue(this, m_jit.graph().varArgChild(node, 1));
+        GPRReg thisValueGPR = thisValue.gpr();
+        JSValueOperand property(this, m_jit.graph().varArgChild(node, 2));
+        GPRReg propertyGPR = property.gpr();
+        JSValueOperand value(this, m_jit.graph().varArgChild(node, 3));
+        GPRReg valueGPR = value.gpr();
+
+        flushRegisters();
+        callOperation(m_jit.isStrictModeFor(node->origin.semantic) ? operationPutByValWithThisStrict : operationPutByValWithThis, NoResult, baseGPR, thisValueGPR, propertyGPR, valueGPR);
+        m_jit.exceptionCheck();
+
+        noResult(node);
+        break;
+    }
+
     case PutByIdDirect: {
         SpeculateCellOperand base(this, node->child1());
         JSValueOperand value(this, node->child2());
diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
index cf81ba5..b5102fa 100644
--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
@@ -169,6 +169,7 @@
     case TryGetById:
     case GetById:
     case GetByIdFlush:
+    case GetByIdWithThis:
     case ToThis:
     case MultiGetByOffset:
     case MultiPutByOffset:
@@ -262,6 +263,8 @@
         if (node->child1().useKind() == CellUse)
             break;
         return CannotCompile;
+    case PutByIdWithThis:
+        break;
     case GetIndexedPropertyStorage:
         if (node->arrayMode().type() == Array::String)
             break;
@@ -326,6 +329,8 @@
             return CannotCompile;
         }
         break;
+    case GetByValWithThis:
+        break;
     case PutByVal:
     case PutByValAlias:
     case PutByValDirect:
@@ -342,6 +347,8 @@
             return CannotCompile;
         }
         break;
+    case PutByValWithThis:
+        break;
     case ArrayPush:
     case ArrayPop:
         switch (node->arrayMode().type()) {
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
index 67bbb00..8b73da1 100644
--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
@@ -605,6 +605,9 @@
         case GetByIdFlush:
             compileGetById(AccessType::Get);
             break;
+        case GetByIdWithThis:
+            compileGetByIdWithThis();
+            break;
         case In:
             compileIn();
             break;
@@ -613,6 +616,9 @@
         case PutByIdFlush:
             compilePutById();
             break;
+        case PutByIdWithThis:
+            compilePutByIdWithThis();
+            break;
         case PutGetterById:
         case PutSetterById:
             compilePutAccessorById();
@@ -649,11 +655,17 @@
         case GetMyArgumentByValOutOfBounds:
             compileGetMyArgumentByVal();
             break;
+        case GetByValWithThis:
+            compileGetByValWithThis();
+            break;
         case PutByVal:
         case PutByValAlias:
         case PutByValDirect:
             compilePutByVal();
             break;
+        case PutByValWithThis:
+            compilePutByValWithThis();
+            break;
         case ArrayPush:
             compileArrayPush();
             break;
@@ -2483,6 +2495,45 @@
             return;
         }
     }
+
+    void compileGetByIdWithThis()
+    {
+        LValue base = lowJSValue(m_node->child1());
+        LValue thisValue = lowJSValue(m_node->child2());
+        LValue result = vmCall(m_out.int64, m_out.operation(operationGetByIdWithThis), m_callFrame, base, thisValue, m_out.constIntPtr(m_graph.identifiers()[m_node->identifierNumber()]));
+        setJSValue(result);
+    }
+
+    void compileGetByValWithThis()
+    {
+        LValue base = lowJSValue(m_node->child1());
+        LValue thisValue = lowJSValue(m_node->child2());
+        LValue subscript = lowJSValue(m_node->child3());
+
+        LValue result = vmCall(m_out.int64, m_out.operation(operationGetByValWithThis), m_callFrame, base, thisValue, subscript);
+        setJSValue(result);
+    }
+
+    void compilePutByIdWithThis()
+    {
+        LValue base = lowJSValue(m_node->child1());
+        LValue thisValue = lowJSValue(m_node->child2());
+        LValue value = lowJSValue(m_node->child3());
+
+        vmCall(m_out.voidType, m_out.operation(m_graph.isStrictModeFor(m_node->origin.semantic) ? operationPutByIdWithThisStrict : operationPutByIdWithThis),
+            m_callFrame, base, thisValue, value, m_out.constIntPtr(m_graph.identifiers()[m_node->identifierNumber()]));
+    }
+
+    void compilePutByValWithThis()
+    {
+        LValue base = lowJSValue(m_graph.varArgChild(m_node, 0));
+        LValue thisValue = lowJSValue(m_graph.varArgChild(m_node, 1));
+        LValue property = lowJSValue(m_graph.varArgChild(m_node, 2));
+        LValue value = lowJSValue(m_graph.varArgChild(m_node, 3));
+
+        vmCall(m_out.voidType, m_out.operation(m_graph.isStrictModeFor(m_node->origin.semantic) ? operationPutByValWithThisStrict : operationPutByValWithThis),
+            m_callFrame, base, thisValue, property, value);
+    }
     
     void compilePutById()
     {
diff --git a/Source/JavaScriptCore/jit/CCallHelpers.cpp b/Source/JavaScriptCore/jit/CCallHelpers.cpp
index 6189ea1..ae189f2 100644
--- a/Source/JavaScriptCore/jit/CCallHelpers.cpp
+++ b/Source/JavaScriptCore/jit/CCallHelpers.cpp
@@ -64,6 +64,107 @@
     storePtr(GPRInfo::regT2, Address(GPRInfo::regT0));
 }
 
+#if NUMBER_OF_ARGUMENT_REGISTERS >= 4
+void CCallHelpers::setupFourStubArgsGPR(GPRReg destA, GPRReg destB, GPRReg destC, GPRReg destD, GPRReg srcA, GPRReg srcB, GPRReg srcC, GPRReg srcD)
+{
+    if (!ASSERT_DISABLED) {
+        RegisterSet destinations(destA, destB, destC, destD);
+        ASSERT_WITH_MESSAGE(destinations.numberOfSetGPRs() == 4, "Destinations should not be aliased.");
+    }
+
+    typedef std::pair<GPRReg, GPRReg> RegPair;
+    Vector<RegPair, 4> pairs;
+
+    if (srcA != destA)
+        pairs.append(std::make_pair(srcA, destA));
+    if (srcB != destB)
+        pairs.append(std::make_pair(srcB, destB));
+    if (srcC != destC)
+        pairs.append(std::make_pair(srcC, destC));
+    if (srcD != destD)
+        pairs.append(std::make_pair(srcD, destD));
+
+
+#if !ASSERT_DISABLED
+    auto numUniqueSources = [&] () -> unsigned {
+        RegisterSet set;
+        for (auto& pair : pairs) {
+            GPRReg source = pair.first;
+            set.set(source);
+        }
+        return set.numberOfSetGPRs();
+    };
+
+    auto numUniqueDests = [&] () -> unsigned {
+        RegisterSet set;
+        for (auto& pair : pairs) {
+            GPRReg dest = pair.second;
+            set.set(dest);
+        }
+        return set.numberOfSetGPRs();
+    };
+#endif
+
+    while (pairs.size()) {
+        RegisterSet freeDestinations;
+        for (auto& pair : pairs) {
+            GPRReg dest = pair.second;
+            freeDestinations.set(dest);
+        }
+        for (auto& pair : pairs) {
+            GPRReg source = pair.first;
+            freeDestinations.clear(source);
+        }
+
+        if (freeDestinations.numberOfSetGPRs()) {
+            bool madeMove = false;
+            for (unsigned i = 0; i < pairs.size(); i++) {
+                auto& pair = pairs[i];
+                GPRReg source = pair.first;
+                GPRReg dest = pair.second;
+                if (freeDestinations.get(dest)) {
+                    move(source, dest);
+                    pairs.remove(i);
+                    madeMove = true;
+                    break;
+                }
+            }
+            ASSERT_UNUSED(madeMove, madeMove);
+            continue;
+        }
+
+        ASSERT(numUniqueDests() == numUniqueSources());
+        ASSERT(numUniqueDests() == pairs.size());
+        // The set of source and destination registers are equivalent sets. This means we don't have
+        // any free destination registers that won't also clobber a source. We get around this by
+        // exchanging registers.
+
+        GPRReg source = pairs[0].first;
+        GPRReg dest = pairs[0].second;
+        swap(source, dest);
+        pairs.remove(0);
+
+        GPRReg newSource = source;
+        for (auto& pair : pairs) {
+            GPRReg source = pair.first;
+            if (source == dest) {
+                pair.first = newSource;
+                break;
+            }
+        }
+
+        // We may have introduced pairs that have the same source and destination. Remove those now.
+        for (unsigned i = 0; i < pairs.size(); i++) {
+            auto& pair = pairs[i];
+            if (pair.first == pair.second) {
+                pairs.remove(i);
+                i--;
+            }
+        }
+    }
+}
+#endif // NUMBER_OF_ARGUMENT_REGISTERS >= 4
+
 } // namespace JSC
 
 #endif // ENABLE(JIT)
diff --git a/Source/JavaScriptCore/jit/CCallHelpers.h b/Source/JavaScriptCore/jit/CCallHelpers.h
index 0faee09..4ddfb7e 100644
--- a/Source/JavaScriptCore/jit/CCallHelpers.h
+++ b/Source/JavaScriptCore/jit/CCallHelpers.h
@@ -30,6 +30,7 @@
 
 #include "AssemblyHelpers.h"
 #include "GPRInfo.h"
+#include "RegisterMap.h"
 #include "StackAlignment.h"
 
 namespace JSC {
@@ -827,6 +828,21 @@
         addCallArgument(arg2);
         addCallArgument(arg3);
     }
+
+    ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5, GPRReg arg6, GPRReg arg7, GPRReg arg8)
+    {
+        resetCallArguments();
+        addCallArgument(GPRInfo::callFrameRegister);
+        addCallArgument(arg1);
+        addCallArgument(arg2);
+        addCallArgument(arg3);
+        addCallArgument(arg4);
+        addCallArgument(arg5);
+        addCallArgument(arg6);
+        addCallArgument(arg7);
+        addCallArgument(arg8);
+    }
+
 #endif // !NUMBER_OF_ARGUMENT_REGISTERS
     // These methods are suitable for any calling convention that provides for
     // at least 4 argument registers, e.g. X86_64, ARMv7.
@@ -913,6 +929,8 @@
             swap(destB, destC);
     }
 
+    void setupFourStubArgsGPR(GPRReg destA, GPRReg destB, GPRReg destC, GPRReg destD, GPRReg srcA, GPRReg srcB, GPRReg srcC, GPRReg srcD);
+
 #if CPU(X86_64) || CPU(ARM64)
     template<FPRReg destA, FPRReg destB>
     void setupTwoStubArgsFPR(FPRReg srcA, FPRReg srcB)
@@ -1951,6 +1969,27 @@
         setupArgumentsWithExecState(arg1, arg2, arg3);
     }
 
+    ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5, GPRReg arg6, GPRReg arg7, GPRReg arg8)
+    {
+        poke(arg8, POKE_ARGUMENT_OFFSET + 4);
+        poke(arg7, POKE_ARGUMENT_OFFSET + 3);
+        poke(arg6, POKE_ARGUMENT_OFFSET + 2);
+        poke(arg5, POKE_ARGUMENT_OFFSET + 1);
+        poke(arg4, POKE_ARGUMENT_OFFSET);
+        setupArgumentsWithExecState(arg1, arg2, arg3);
+    }
+
+    ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5, GPRReg arg6, GPRReg arg7, GPRReg arg8, GPRReg arg9)
+    {
+        poke(arg9, POKE_ARGUMENT_OFFSET + 5);
+        poke(arg8, POKE_ARGUMENT_OFFSET + 4);
+        poke(arg7, POKE_ARGUMENT_OFFSET + 3);
+        poke(arg6, POKE_ARGUMENT_OFFSET + 2);
+        poke(arg5, POKE_ARGUMENT_OFFSET + 1);
+        poke(arg4, POKE_ARGUMENT_OFFSET);
+        setupArgumentsWithExecState(arg1, arg2, arg3);
+    }
+
     ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, GPRReg arg2, GPRReg arg3, TrustedImm32 arg4, TrustedImm32 arg5, GPRReg arg6, GPRReg arg7)
     {
         poke(arg7, POKE_ARGUMENT_OFFSET + 3);
@@ -1986,6 +2025,12 @@
 #endif // NUMBER_OF_ARGUMENT_REGISTERS == 4
 
 #if NUMBER_OF_ARGUMENT_REGISTERS >= 5
+    ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4)
+    {
+        setupFourStubArgsGPR(GPRInfo::argumentGPR1, GPRInfo::argumentGPR2, GPRInfo::argumentGPR3, GPRInfo::argumentGPR4, arg1, arg2, arg3, arg4);
+        move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+    }
+
     void setupStubArguments134(GPRReg arg1, GPRReg arg3, GPRReg arg4)
     {
         setupThreeStubArgsGPR<GPRInfo::argumentGPR1, GPRInfo::argumentGPR3, GPRInfo::argumentGPR4>(arg1, arg3, arg4);
@@ -2036,7 +2081,7 @@
         move(arg4, GPRInfo::argumentGPR4);
         move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
     }
-    
+
     ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, GPRReg arg2, TrustedImm32 arg3, TrustedImm32 arg4)
     {
         move(arg2, GPRInfo::argumentGPR2); // In case arg2 is argumentGPR1.
diff --git a/Source/JavaScriptCore/jit/GPRInfo.h b/Source/JavaScriptCore/jit/GPRInfo.h
index 8b40bdb..437be62 100644
--- a/Source/JavaScriptCore/jit/GPRInfo.h
+++ b/Source/JavaScriptCore/jit/GPRInfo.h
@@ -880,20 +880,6 @@
 
 #endif // CPU(SH4)
 
-inline GPRReg argumentRegisterFor(unsigned argumentIndex)
-{
-#if USE(JSVALUE64)
-    if (argumentIndex >= NUMBER_OF_ARGUMENT_REGISTERS)
-        return InvalidGPRReg;
-
-    return GPRInfo::toArgumentRegister(argumentIndex);
-#else
-    UNUSED_PARAM(argumentIndex);
-
-    return InvalidGPRReg;
-#endif
-}
-
 // The baseline JIT uses "accumulator" style execution with regT0 (for 64-bit)
 // and regT0 + regT1 (for 32-bit) serving as the accumulator register(s) for
 // passing results of one opcode to the next. Hence:
diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp
index 2a0c8bb..c228a85 100644
--- a/Source/JavaScriptCore/jit/JIT.cpp
+++ b/Source/JavaScriptCore/jit/JIT.cpp
@@ -237,7 +237,9 @@
         DEFINE_OP(op_try_get_by_id)
         case op_get_array_length:
         DEFINE_OP(op_get_by_id)
+        DEFINE_OP(op_get_by_id_with_this)
         DEFINE_OP(op_get_by_val)
+        DEFINE_OP(op_get_by_val_with_this)
         DEFINE_OP(op_overrides_has_instance)
         DEFINE_OP(op_instanceof)
         DEFINE_OP(op_instanceof_custom)
@@ -292,9 +294,11 @@
         DEFINE_OP(op_create_lexical_environment)
         DEFINE_OP(op_get_parent_scope)
         DEFINE_OP(op_put_by_id)
+        DEFINE_OP(op_put_by_id_with_this)
         DEFINE_OP(op_put_by_index)
         case op_put_by_val_direct:
         DEFINE_OP(op_put_by_val)
+        DEFINE_OP(op_put_by_val_with_this)
         DEFINE_OP(op_put_getter_by_id)
         DEFINE_OP(op_put_setter_by_id)
         DEFINE_OP(op_put_getter_setter_by_id)
diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h
index 37a26ed..075cfe1 100644
--- a/Source/JavaScriptCore/jit/JIT.h
+++ b/Source/JavaScriptCore/jit/JIT.h
@@ -507,6 +507,8 @@
         void emit_op_eq_null(Instruction*);
         void emit_op_try_get_by_id(Instruction*);
         void emit_op_get_by_id(Instruction*);
+        void emit_op_get_by_id_with_this(Instruction*);
+        void emit_op_get_by_val_with_this(Instruction*);
         void emit_op_get_arguments_length(Instruction*);
         void emit_op_get_by_val(Instruction*);
         void emit_op_get_argument_by_val(Instruction*);
@@ -565,8 +567,10 @@
         void emit_op_create_lexical_environment(Instruction*);
         void emit_op_get_parent_scope(Instruction*);
         void emit_op_put_by_id(Instruction*);
+        void emit_op_put_by_id_with_this(Instruction*);
         void emit_op_put_by_index(Instruction*);
         void emit_op_put_by_val(Instruction*);
+        void emit_op_put_by_val_with_this(Instruction*);
         void emit_op_put_getter_by_id(Instruction*);
         void emit_op_put_setter_by_id(Instruction*);
         void emit_op_put_getter_setter_by_id(Instruction*);
diff --git a/Source/JavaScriptCore/jit/JITOperations.h b/Source/JavaScriptCore/jit/JITOperations.h
index f891847..db7d978f 100644
--- a/Source/JavaScriptCore/jit/JITOperations.h
+++ b/Source/JavaScriptCore/jit/JITOperations.h
@@ -156,6 +156,7 @@
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EZZ)(ExecState*, int32_t, int32_t);
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EZSymtabJ)(ExecState*, int32_t, SymbolTable*, EncodedJSValue);
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EOIUi)(ExecState*, JSObject*, UniquedStringImpl*, uint32_t);
+typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJJI)(ExecState*, EncodedJSValue, EncodedJSValue, UniquedStringImpl*);
 typedef JSCell* JIT_OPERATION (*C_JITOperation_E)(ExecState*);
 typedef JSCell* JIT_OPERATION (*C_JITOperation_EZ)(ExecState*, int32_t);
 typedef JSCell* JIT_OPERATION (*C_JITOperation_EC)(ExecState*, JSCell*);
@@ -249,6 +250,8 @@
 typedef void JIT_OPERATION (*V_JITOperation_EPc)(ExecState*, Instruction*);
 typedef void JIT_OPERATION (*V_JITOperation_EPZJ)(ExecState*, void*, int32_t, EncodedJSValue);
 typedef void JIT_OPERATION (*V_JITOperation_ESsiJJI)(ExecState*, StructureStubInfo*, EncodedJSValue, EncodedJSValue, UniquedStringImpl*);
+typedef void JIT_OPERATION (*V_JITOperation_EJJJI)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, UniquedStringImpl*);
+typedef void JIT_OPERATION (*V_JITOperation_EJJJJ)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, EncodedJSValue);
 typedef void JIT_OPERATION (*V_JITOperation_EWs)(ExecState*, WatchpointSet*);
 typedef void JIT_OPERATION (*V_JITOperation_EZ)(ExecState*, int32_t);
 typedef void JIT_OPERATION (*V_JITOperation_EZJ)(ExecState*, int32_t, EncodedJSValue);
diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp
index 494bd2b..eb87585 100644
--- a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp
+++ b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp
@@ -313,6 +313,12 @@
     m_byValCompilationInfo.append(ByValCompilationInfo(byValInfo, m_bytecodeOffset, notIndex, badType, mode, profile, done, done));
 }
 
+void JIT::emit_op_put_by_val_with_this(Instruction* currentInstruction)
+{
+    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_put_by_val_with_this);
+    slowPathCall.call();
+}
+
 JIT::JumpList JIT::emitGenericContiguousPutByVal(Instruction* currentInstruction, PatchableJump& badType, IndexingType indexingShape)
 {
     int value = currentInstruction[3].u.operand;
@@ -603,6 +609,18 @@
     emitPutVirtualRegister(resultVReg);
 }
 
+void JIT::emit_op_get_by_id_with_this(Instruction* currentInstruction)
+{
+    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_by_id_with_this);
+    slowPathCall.call();
+}
+
+void JIT::emit_op_get_by_val_with_this(Instruction* currentInstruction)
+{
+    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_by_val_with_this);
+    slowPathCall.call();
+}
+
 void JIT::emitSlow_op_get_by_id(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
     int resultVReg = currentInstruction[1].u.operand;
@@ -648,6 +666,12 @@
     m_putByIds.append(gen);
 }
 
+void JIT::emit_op_put_by_id_with_this(Instruction* currentInstruction)
+{
+    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_put_by_id_with_this);
+    slowPathCall.call();
+}
+
 void JIT::emitSlow_op_put_by_id(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
     int baseVReg = currentInstruction[1].u.operand;
diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
index 38b0729..6a3c464 100644
--- a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
+++ b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
@@ -1163,6 +1163,30 @@
     store32(regT2, Address(regT0, DirectArguments::storageOffset() + index * sizeof(WriteBarrier<Unknown>) + PayloadOffset));
 }
 
+void JIT::emit_op_get_by_id_with_this(Instruction* currentInstruction)
+{
+    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_by_id_with_this);
+    slowPathCall.call();
+}
+
+void JIT::emit_op_get_by_val_with_this(Instruction* currentInstruction)
+{
+    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_by_val_with_this);
+    slowPathCall.call();
+}
+
+void JIT::emit_op_put_by_id_with_this(Instruction* currentInstruction)
+{
+    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_put_by_id_with_this);
+    slowPathCall.call();
+}
+
+void JIT::emit_op_put_by_val_with_this(Instruction* currentInstruction)
+{
+    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_put_by_val_with_this);
+    slowPathCall.call();
+}
+
 } // namespace JSC
 
 #endif // USE(JSVALUE32_64)
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
index 290c3c4..a2441de 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
@@ -1752,6 +1752,25 @@
     callSlowPath(_llint_slow_path_instanceof)
     dispatch(4)
 
+_llint_op_get_by_id_with_this:
+    traceExecution()
+    callSlowPath(_slow_path_get_by_id_with_this)
+    dispatch(5)
+
+_llint_op_get_by_val_with_this:
+    traceExecution()
+    callSlowPath(_slow_path_get_by_val_with_this)
+    dispatch(5)
+
+_llint_op_put_by_id_with_this:
+    traceExecution()
+    callSlowPath(_slow_path_put_by_id_with_this)
+    dispatch(5)
+
+_llint_op_put_by_val_with_this:
+    traceExecution()
+    callSlowPath(_slow_path_put_by_val_with_this)
+    dispatch(5)
 
 # Lastly, make sure that we can link even though we don't support all opcodes.
 # These opcodes should never arise when using LLInt or either JIT. We assert
diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
index 11dd2e2..92d252c 100644
--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
@@ -815,4 +815,78 @@
     END();
 }
 
+SLOW_PATH_DECL(slow_path_get_by_id_with_this)
+{
+    BEGIN();
+    const Identifier& ident = exec->codeBlock()->identifier(pc[4].u.operand);
+    JSValue baseValue = OP_C(2).jsValue();
+    JSValue thisVal = OP_C(3).jsValue();
+    PropertySlot slot(thisVal, PropertySlot::PropertySlot::InternalMethodType::Get);
+    JSValue result = baseValue.get(exec, ident, slot);
+    RETURN(result);
+}
+
+SLOW_PATH_DECL(slow_path_get_by_val_with_this)
+{
+    BEGIN();
+
+    JSValue baseValue = OP_C(2).jsValue();
+    JSValue thisValue = OP_C(3).jsValue();
+    JSValue subscript = OP_C(4).jsValue();
+
+    if (LIKELY(baseValue.isCell() && subscript.isString())) {
+        VM& vm = exec->vm();
+        Structure& structure = *baseValue.asCell()->structure(vm);
+        if (JSCell::canUseFastGetOwnProperty(structure)) {
+            if (RefPtr<AtomicStringImpl> existingAtomicString = asString(subscript)->toExistingAtomicString(exec)) {
+                if (JSValue result = baseValue.asCell()->fastGetOwnProperty(vm, structure, existingAtomicString.get()))
+                    RETURN(result); 
+            }
+        }
+    }
+    
+    PropertySlot slot(thisValue, PropertySlot::PropertySlot::InternalMethodType::Get);
+    if (subscript.isUInt32()) {
+        uint32_t i = subscript.asUInt32();
+        if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i))
+            RETURN(asString(baseValue)->getIndex(exec, i));
+        
+        RETURN(baseValue.get(exec, i, slot));
+    }
+
+    baseValue.requireObjectCoercible(exec);
+    CHECK_EXCEPTION();
+    auto property = subscript.toPropertyKey(exec);
+    CHECK_EXCEPTION();
+    RETURN(baseValue.get(exec, property, slot));
+}
+
+SLOW_PATH_DECL(slow_path_put_by_id_with_this)
+{
+    BEGIN();
+    CodeBlock* codeBlock = exec->codeBlock();
+    const Identifier& ident = codeBlock->identifier(pc[3].u.operand);
+    JSValue baseValue = OP_C(1).jsValue();
+    JSValue thisVal = OP_C(2).jsValue();
+    JSValue putValue = OP_C(4).jsValue();
+    PutPropertySlot slot(thisVal, codeBlock->isStrictMode(), codeBlock->putByIdContext());
+    baseValue.putInline(exec, ident, putValue, slot);
+    END();
+}
+
+SLOW_PATH_DECL(slow_path_put_by_val_with_this)
+{
+    BEGIN();
+    JSValue baseValue = OP_C(1).jsValue();
+    JSValue thisValue = OP_C(2).jsValue();
+    JSValue subscript = OP_C(3).jsValue();
+    JSValue value = OP_C(4).jsValue();
+    
+    auto property = subscript.toPropertyKey(exec);
+    CHECK_EXCEPTION();
+    PutPropertySlot slot(thisValue, exec->codeBlock()->isStrictMode());
+    baseValue.put(exec, property, value, slot);
+    END();
+}
+
 } // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.h b/Source/JavaScriptCore/runtime/CommonSlowPaths.h
index 43a88c4..abcb71f 100644
--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.h
+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.h
@@ -248,6 +248,10 @@
 SLOW_PATH_HIDDEN_DECL(slow_path_push_with_scope);
 SLOW_PATH_HIDDEN_DECL(slow_path_resolve_scope);
 SLOW_PATH_HIDDEN_DECL(slow_path_copy_rest);
+SLOW_PATH_HIDDEN_DECL(slow_path_get_by_id_with_this);
+SLOW_PATH_HIDDEN_DECL(slow_path_get_by_val_with_this);
+SLOW_PATH_HIDDEN_DECL(slow_path_put_by_id_with_this);
+SLOW_PATH_HIDDEN_DECL(slow_path_put_by_val_with_this);
 
 } // namespace JSC
 
diff --git a/Source/JavaScriptCore/tests/stress/super-property-access-exceptions.js b/Source/JavaScriptCore/tests/stress/super-property-access-exceptions.js
new file mode 100644
index 0000000..cf413c1
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/super-property-access-exceptions.js
@@ -0,0 +1,153 @@
+function assert(b, m = "Bad!") {
+    if (!b) {
+        throw new Error(m);
+    }
+}
+
+function test(f, iters = 1000) {
+    for (let i = 0; i < iters; i++)
+        f();
+}
+
+test(function() {
+    function fooProp() { return 'foo'; }
+    noInline(fooProp);
+
+    let shouldThrow = false;
+    class A {
+        get foo() {
+            if (shouldThrow)
+                throw new Error;
+            return 20;
+        }
+        get x() { return this._x; }
+    }
+
+    class B extends A {
+        constructor(x) {
+            super();
+            this._x = x;
+        }
+
+        bar() {
+            this._x = super.foo;
+        }
+
+        baz() {
+            this._x = super[fooProp()];
+        }
+    }
+
+    function foo(i) { 
+        let b = new B(i);
+        noInline(b.__lookupGetter__('foo'));
+        let threw = false;
+        try {
+            b.bar();    
+        } catch(e) {
+            threw = true;
+        }
+        if (threw)
+            assert(b.x === i);
+        else
+            assert(b.x === 20);
+    }
+    function bar(i) { 
+        let b = new B(i);
+        noInline(b.__lookupGetter__('foo'));
+        let threw = false;
+        try {
+            b.baz();    
+        } catch(e) {
+            threw = true;
+        }
+        if (threw)
+            assert(b.x === i);
+        else
+            assert(b.x === 20, "b.x " + b.x + "  " + i);
+    }
+    noInline(bar);
+
+    for (let i = 0; i < 10000; i++) {
+        foo(i);
+        bar(i);
+    }
+    shouldThrow = true;
+    foo(23);
+    bar(24);
+
+}, 1);
+
+test(function() {
+    function fooProp() { return 'foo'; }
+    noInline(fooProp);
+
+    function func(i) {
+        if (shouldThrow)
+            throw new Error();
+        return i;
+    }
+    noInline(func);
+
+    let shouldThrow = false;
+    class A {
+        set foo(x) {
+            this._x = x;
+        }
+        get x() { return this._x; }
+    }
+
+    class B extends A {
+        constructor(x) {
+            super();
+            this._x = x;
+        }
+
+        bar(x) {
+            super.foo = func(x);
+        }
+
+        baz(x) {
+            super[fooProp()] = func(x);
+        }
+    }
+
+    function foo(i) { 
+        let b = new B(i);
+        noInline(b.__lookupGetter__('foo'));
+        let threw = false;
+        try {
+            b.bar(i + 1);
+        } catch(e) {
+            threw = true;
+        }
+        if (threw)
+            assert(b.x === i);
+        else
+            assert(b.x === i + 1);
+    }
+    function bar(i) { 
+        let b = new B(i);
+        noInline(b.__lookupGetter__('foo'));
+        let threw = false;
+        try {
+            b.baz(i + 1);
+        } catch(e) {
+            threw = true;
+        }
+        if (threw)
+            assert(b.x === i);
+        else
+            assert(b.x === i + 1);
+    }
+    noInline(bar);
+
+    for (let i = 0; i < 10000; i++) {
+        foo(i);
+        bar(i);
+    }
+    shouldThrow = true;
+    foo(23);
+    bar(24);
+
+}, 1);
diff --git a/Source/JavaScriptCore/tests/stress/super-property-access-tdz.js b/Source/JavaScriptCore/tests/stress/super-property-access-tdz.js
new file mode 100644
index 0000000..3abbf20
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/super-property-access-tdz.js
@@ -0,0 +1,92 @@
+function assert(b, m = "Bad!") {
+    if (!b) {
+        throw new Error(m);
+    }
+}
+
+function test(f, iters = 1000) {
+    for (let i = 0; i < iters; i++)
+        f();
+}
+
+function shouldThrowTDZ(f) {
+    let threw = false;
+    try {
+        f();
+    } catch(e) {
+        assert(e instanceof ReferenceError);
+        assert(e.toString() === "ReferenceError: Cannot access uninitialized variable.");
+        threw = true;
+    }
+    assert(threw);
+}
+
+test(function() {
+    class A {
+        get foo() {
+            return this._x;
+        }
+        set foo(x) {
+            this._x = x;
+        }
+    }
+
+    function fooProp() { return 'foo'; }
+
+    class B extends A {
+        constructor() {
+            super.foo = 20;
+        }
+    }
+
+    class C extends A {
+        constructor() {
+            super[fooProp()] = 20;
+        }
+    }
+
+    class D extends A {
+        constructor() {
+            super[fooProp()];
+        }
+    }
+
+    class E extends A {
+        constructor() {
+            super.foo;
+        }
+    }
+
+    class F extends A {
+        constructor() {
+            (() => super.foo = 20)();
+        }
+    }
+
+    class G extends A {
+        constructor() {
+            (() => super[fooProp()] = 20)();
+        }
+    }
+
+    class H extends A {
+        constructor() {
+            (() => super[fooProp()])();
+        }
+    }
+
+    class I extends A {
+        constructor() {
+            (() => super.foo)();
+        }
+    }
+
+    shouldThrowTDZ(function() { new B; });
+    shouldThrowTDZ(function() { new C; });
+    shouldThrowTDZ(function() { new D; });
+    shouldThrowTDZ(function() { new E; });
+    shouldThrowTDZ(function() { new F; });
+    shouldThrowTDZ(function() { new G; });
+    shouldThrowTDZ(function() { new H; });
+    shouldThrowTDZ(function() { new I; });
+});
diff --git a/Source/JavaScriptCore/tests/stress/super-property-access.js b/Source/JavaScriptCore/tests/stress/super-property-access.js
new file mode 100644
index 0000000..3162537
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/super-property-access.js
@@ -0,0 +1,586 @@
+function assert(b, m = "Bad!") {
+    if (!b) {
+        throw new Error(m);
+    }
+}
+
+function test(f, iters = 1000) {
+    for (let i = 0; i < iters; i++)
+        f();
+}
+
+function func(x) {
+    return x;
+}
+noInline(func);
+
+test(function() {
+    class A {
+        constructor(x)
+        {
+            this._value = x;
+        }
+
+        set value(x) { this._value = x; }
+        get value() { return this._value; }
+    }
+
+    class B extends A {
+        set value(x) { super.value = x; }
+        get value() { return super.value; }
+    }
+
+    let arr = [];
+    for (let i = 0; i < 1000; i++) {
+        arr.push(new B(20));
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].value === 20);
+    }
+    for (let i = 0; i < 1000; i++) {
+        arr[i].value = i;
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].value === i);
+    }
+}, 10);
+
+test(function() {
+    function value() { return 'value'; }
+    noInline(value);
+
+    class A {
+        constructor(x, f = func)
+        {
+            this._value = x;
+            this._func = f;
+        }
+
+        set value(x) { this._value = x; }
+        get value() { return this._value; }
+        get func() { return this._func; }
+    }
+
+    class B extends A {
+        set value(x) { super[value()] = x; }
+        get value() { return super[value()]; }
+        inc() { return super[value()]++; }
+        dec() { return super[value()]--; }
+        preInc() { return ++super[value()]; }
+        preDec() { return --super[value()]; }
+        plusEq(x) { super[value()] += x; }
+        minusEq(x) { super[value()] -= x; }
+        timesEq(x) { super[value()] *= x; }
+        divEq(x) { super[value()] /= x; }
+
+        funcDot(x) { return super.func(x); }
+        funcBracket(x) { return super.func(x); }
+    }
+
+    let arr = [];
+    for (let i = 0; i < 1000; i++) {
+        arr.push(new B(20));
+    }
+    for (let i = 0; i < 1000; i++) {
+        let t = arr[i].value;
+        assert(t === 20);
+    }
+    for (let i = 0; i < 1000; i++) {
+        arr[i].value = i;
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].value === i);
+    }
+
+    for (let i = 0; i < 1000; i++) {
+        let v = arr[i].inc();
+        assert(v === i);
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].value === i+1);
+    }
+
+    for (let i = 0; i < 1000; i++) {
+        let v = arr[i].dec();
+        assert(v === i+1);
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].value === i);
+    }
+
+    for (let i = 0; i < 1000; i++) {
+        let v = arr[i].preInc();
+        assert(v === i+1);
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].value === i+1);
+    }
+
+    for (let i = 0; i < 1000; i++) {
+        let v = arr[i].preDec();
+        assert(v === i);
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].value === i);
+    }
+
+    for (let i = 0; i < 1000; i++) {
+        arr[i].plusEq(i);
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].value === i+i);
+    }
+
+    for (let i = 0; i < 1000; i++) {
+        arr[i].minusEq(i);
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].value === i);
+    }
+
+    for (let i = 0; i < 1000; i++) {
+        arr[i].timesEq(i);
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].value === i*i);
+    }
+
+    for (let i = 0; i < 1000; i++) {
+        if (i === 0)
+            arr[i].value = 0;
+        else
+            arr[i].divEq(i);
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].value === i);
+    }
+
+    for (let i = 0; i < 1000; i++) {
+        arr[i] = new B(0, function(a) { return i + a; });
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].funcDot(i) === i + i);
+        assert(arr[i].funcBracket(i*2) === i + i*2);
+    }
+
+}, 10);
+
+
+test(function() {
+    class A {
+        constructor(x, f = func)
+        {
+            this._value = x;
+            this._func = f;
+        }
+
+        set value(x) { this._value = x; }
+        get value() { return this._value; }
+        get func() { return this._func; }
+    }
+
+    class B extends A {
+        set value(x) { (() => super.value = x)(); }
+        get value() { return (() => super.value)(); }
+        inc() { return (() => super.value++)(); }
+        dec() { return (() => super.value--)(); }
+        preInc() { return (() => ++super.value)(); }
+        preDec() { return (() => --super.value)(); }
+        plusEq(x) { (() => super.value += x)(); }
+        minusEq(x) { (() => super.value -= x)(); }
+        timesEq(x) { (() => super.value *= x)(); }
+        divEq(x) { (() => super.value /= x)(); }
+
+        funcDot(x) { return (() => super.func(x))(); }
+        funcBracket(x) { return (() => super.func(x))(); }
+    }
+
+    let arr = [];
+    for (let i = 0; i < 1000; i++) {
+        arr.push(new B(20));
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].value === 20);
+    }
+    for (let i = 0; i < 1000; i++) {
+        arr[i].value = i;
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].value === i);
+    }
+
+    for (let i = 0; i < 1000; i++) {
+        let v = arr[i].inc();
+        assert(v === i);
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].value === i+1);
+    }
+
+    for (let i = 0; i < 1000; i++) {
+        let v = arr[i].dec();
+        assert(v === i+1);
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].value === i);
+    }
+
+    for (let i = 0; i < 1000; i++) {
+        let v = arr[i].preInc();
+        assert(v === i+1);
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].value === i+1);
+    }
+
+    for (let i = 0; i < 1000; i++) {
+        let v = arr[i].preDec();
+        assert(v === i);
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].value === i);
+    }
+
+    for (let i = 0; i < 1000; i++) {
+        arr[i].plusEq(i);
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].value === i+i);
+    }
+
+    for (let i = 0; i < 1000; i++) {
+        arr[i].minusEq(i);
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].value === i);
+    }
+
+    for (let i = 0; i < 1000; i++) {
+        arr[i].timesEq(i);
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].value === i*i);
+    }
+
+    for (let i = 0; i < 1000; i++) {
+        if (i === 0)
+            arr[i].value = 0;
+        else
+            arr[i].divEq(i);
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].value === i);
+    }
+
+    for (let i = 0; i < 1000; i++) {
+        arr[i] = new B(0, function(a) { return i + a; });
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].funcDot(i) === i + i);
+        assert(arr[i].funcBracket(i*2) === i + i*2);
+    }
+
+}, 10);
+
+test(function() {
+    function foo() { return 'foo'; }
+    noInline(foo);
+    class A { }
+    let obj = {};
+    A.prototype.foo = obj;
+    A.prototype[0] = obj;
+
+
+    class B extends A {
+        baz() { return super[foo()]; }
+        jaz() { return super.foo; }
+        bar() { return super[0]; }
+        
+    }
+
+    assert((new B).baz() === obj);
+    assert((new B).jaz() === obj);
+    assert((new B).bar() === obj);
+});
+
+test(function() {
+    class A { }
+    for (let i = 0; i < 1000; i++)
+        A.prototype[i] = i;
+
+
+    class B extends A {
+        index(i) { return super[i]; }
+    }
+
+    let b = new B;
+    for (let i = 0; i < 1000; i++) {
+        assert(b.index(i) === i);
+    }
+}, 50);
+
+test(function() {
+    let obj = {};
+    class A { constructor(r) { this._foo = r; } }
+    Object.defineProperty(A.prototype, '0', { get: function() { return this._foo; } });
+
+    class B extends A {
+        bar() { return super[0]; }
+    }
+
+    let rand = Math.random();
+    assert((new B(rand)).bar() === rand);
+});
+
+test(function() { class A {
+        constructor() { this._array = []; }
+        set foo(x) {
+            this._array.push(x);
+        }
+        get array() { return this._array; }
+    }
+
+    class B extends A {
+        baz(i) {
+            let o = {x:20, y:30, [i]:i};
+            for (super.foo in o) { }
+        }
+    }
+    let arr = [];
+    for (let i = 0; i < 20; i++)
+        arr.push(new B);
+    for (let i = 0; i < arr.length; i++) {
+        let obj = arr[i];
+        obj.baz(i);
+    }
+    for (let i = 0; i < arr.length; i++) {
+        let obj = arr[i].array;
+        assert(obj.length === 3)
+        assert(obj[0] === '' + i);
+        assert(obj[1] === 'x')
+        assert(obj[2] === 'y')
+    }
+}, 1000);
+
+test(function() {
+    function foo() { return 'foo'; }
+    noInline(foo);
+    class A {
+        constructor() { this._array = []; }
+        set foo(x) {
+            this._array.push(x);
+        }
+        get array() { return this._array; }
+    }
+
+    class B extends A {
+        baz(i) {
+            let o = {x:20, y:30, [i]:i};
+            for (super[foo()] in o) { }
+        }
+    }
+    let arr = [];
+    for (let i = 0; i < 20; i++)
+        arr.push(new B);
+    for (let i = 0; i < arr.length; i++) {
+        let obj = arr[i];
+        obj.baz(i);
+    }
+    for (let i = 0; i < arr.length; i++) {
+        let obj = arr[i].array;
+        assert(obj.length === 3)
+        assert(obj[0] === '' + i);
+        assert(obj[1] === 'x')
+        assert(obj[2] === 'y')
+    }
+}, 1000);
+
+test(function() {
+    class A {
+        constructor() { this._array = []; }
+        set foo(x) {
+            this._array.push(x);
+        }
+        get array() { return this._array; }
+    }
+
+    class B extends A {
+        baz(i) {
+            let o = ['' + i, "x", "y"];
+            for (super.foo of o) { }
+        }
+    }
+    let arr = [];
+    for (let i = 0; i < 20; i++)
+        arr.push(new B);
+    for (let i = 0; i < arr.length; i++) {
+        let obj = arr[i];
+        obj.baz(i);
+    }
+    for (let i = 0; i < arr.length; i++) {
+        let obj = arr[i].array;
+        assert(obj.length === 3)
+        assert(obj[0] === '' + i);
+        assert(obj[1] === 'x')
+        assert(obj[2] === 'y')
+    }
+}, 1000);
+
+test(function() {
+    function foo() { return 'foo'; }
+    class A {
+        constructor() { this._array = []; }
+        set foo(x) {
+            this._array.push(x);
+        }
+        get array() { return this._array; }
+    }
+
+    class B extends A {
+        baz(i) {
+            let o = ['' + i, "x", "y"];
+            for (super[foo()] of o) { }
+        }
+    }
+    let arr = [];
+    for (let i = 0; i < 20; i++)
+        arr.push(new B);
+    for (let i = 0; i < arr.length; i++) {
+        let obj = arr[i];
+        obj.baz(i);
+    }
+    for (let i = 0; i < arr.length; i++) {
+        let obj = arr[i].array;
+        assert(obj.length === 3)
+        assert(obj[0] === '' + i);
+        assert(obj[1] === 'x')
+        assert(obj[2] === 'y')
+    }
+}, 1000);
+
+test(function() {
+    class A {
+        constructor() {
+            this._foo = null;
+        }
+        set foo(x) {
+            this._foo = x;
+        }
+        get foo() { return this._foo; }
+    }
+    function obj(i) { return {o: i}; }
+    noInline(obj);
+
+    class B extends A {
+        baz(i) {
+            ;({o: super.foo} = obj(i));
+        }
+    }
+    let arr = [];
+    for (let i = 0; i < 1000; i++) {
+        arr.push((new B));
+    }
+    for (let i = 0; i < 1000; i++) {
+        arr[i].baz(i);
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].foo === i);
+    }
+}, 100);
+
+test(function() {
+    function foo() { return 'foo'; }
+    noInline(foo);
+    class A {
+        constructor() {
+            this._foo = null;
+        }
+        set foo(x) {
+            this._foo = x;
+        }
+        get foo() { return this._foo; }
+    }
+    function obj(i) { return {o: i}; }
+    noInline(obj);
+
+    class B extends A {
+        baz(i) {
+            ;({o: super[foo()]} = obj(i));
+        }
+    }
+    let arr = [];
+    for (let i = 0; i < 1000; i++) {
+        arr.push((new B));
+    }
+    for (let i = 0; i < 1000; i++) {
+        arr[i].baz(i);
+    }
+    for (let i = 0; i < 1000; i++) {
+        assert(arr[i].foo === i);
+    }
+}, 100);
+
+test(function() {
+    class A {
+        constructor() {
+            this._foo = null;
+        }
+        get call() {
+            let ret = () => 'call';
+            noInline(ret);
+            return ret;
+        }
+        get apply() { 
+            let ret = () => 'apply';
+            noInline(ret);
+            return ret;
+        }
+    }
+
+    class B extends A {
+        foo() {
+            return super.call({}, 20, 30);
+        }
+        bar() {
+            return super.apply({}, [10, 20]);
+        }
+    }
+    for (let i = 0; i < 100; i++) {
+        let b = new B;
+        assert(b.foo() === 'call');
+        assert(b.bar() === 'apply');
+    }
+});
+
+test(function() {
+    class A {
+        constructor(i) { this._i = i; }
+        get foo() {
+            return function(strings, ...values) {
+                return [strings, values];
+            }
+        }
+        get i() { return this._i; }
+    }
+
+    class B extends A {
+        baz() {
+            return super.foo`hello${super.i}world`;
+        }
+    }
+
+    let arr = [];
+    for (let i = 0; i < 1000; i++) {
+        let b = new B(i);
+        arr.push(b);
+    }
+    for (let i = 0; i < 1000; i++) {
+        let r = arr[i].baz();
+        assert(r.length === 2);
+        assert(r[0].length === 2);
+        assert(r[0][0] === 'hello');
+        assert(r[0][1] === 'world');
+        assert(r[1].length === 1);
+        assert(r[1][0] === i);
+    }
+});