Commit 19afeced authored by barraclough@apple.com's avatar barraclough@apple.com

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

Global strict mode function leaking global object as "this".

Reviewed by Oliver Hunt.

Source/JavaScriptCore: 

The root problem here is that we pass the wrong values into
calls, and then try to fix them up in the callee. Correct
behaviour per the spec is to pass in the value undefined,
as this unless either (1) the function call is based on an
explicit property access or (2) the base of the call comes
directly from a 'with'.

This change does away with the need for this conversion of
objects (non strict code should only box primitives), and
does away with all this conversion for strict functions.

This patch may have web compatibility ramifications, and may
require some advocacy.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dump):
    - Removed op_convert_this_strict, added op_resolve_with_this.
* bytecode/Opcode.h:
    - Removed op_convert_this_strict, added op_resolve_with_this.
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitResolveWithThis):
    - Removed op_convert_this_strict, added op_resolve_with_this.
* bytecompiler/BytecodeGenerator.h:
    - Removed op_convert_this_strict, added op_resolve_with_this.
* bytecompiler/NodesCodegen.cpp:
(JSC::EvalFunctionCallNode::emitBytecode):
(JSC::FunctionCallResolveNode::emitBytecode):
    - Removed op_convert_this_strict, added op_resolve_with_this.
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compile):
    - Change NeedsThisConversion check to test for JSString's vptr
      (objects no longer need conversion).
* interpreter/Interpreter.cpp:
(JSC::Interpreter::resolveThisAndProperty):
    - Based on resolveBaseAndProperty, but produce correct this value.
(JSC::Interpreter::privateExecute):
    - Removed op_convert_this_strict, added op_resolve_with_this.
* interpreter/Interpreter.h:
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
    - Removed op_convert_this_strict, added op_resolve_with_this.
* jit/JIT.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_resolve_with_this):
    - Removed op_convert_this_strict, added op_resolve_with_this.
(JSC::JIT::emit_op_convert_this):
(JSC::JIT::emitSlow_op_convert_this):
    - Change NeedsThisConversion check to test for JSString's vptr
      (objects no longer need conversion).
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_resolve_with_this):
    - Removed op_convert_this_strict, added op_resolve_with_this.
(JSC::JIT::emit_op_convert_this):
(JSC::JIT::emitSlow_op_convert_this):
    - Change NeedsThisConversion check to test for JSString's vptr
      (objects no longer need conversion).
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
    - Removed op_convert_this_strict, added op_resolve_with_this.
* jit/JITStubs.h:
    - Removed op_convert_this_strict, added op_resolve_with_this.
* runtime/JSActivation.h:
    - removed NeedsThisConversion flag, added IsEnvironmentRecord.
* runtime/JSStaticScopeObject.h:
    - removed NeedsThisConversion flag, added IsEnvironmentRecord.
* runtime/JSString.h:
(JSC::RopeBuilder::createStructure):
    - removed NeedsThisConversion.
* runtime/JSTypeInfo.h:
(JSC::TypeInfo::isEnvironmentRecord):
(JSC::TypeInfo::overridesHasInstance):
    - removed NeedsThisConversion flag, added IsEnvironmentRecord.
* runtime/JSValue.h:
    - removed NeedsThisConversion.
* runtime/JSVariableObject.h:
    - Corrected StructureFlags inheritance.
* runtime/StrictEvalActivation.h:
(JSC::StrictEvalActivation::createStructure):
    - Added IsEnvironmentRecord to StructureFlags, addded createStructure.
* runtime/Structure.h:
    - removed NeedsThisConversion.
* tests/mozilla/ecma/String/15.5.4.6-2.js:
(getTestCases):
    - Removed invalid test case.

Source/WebCore: 

* bindings/js/JSMainThreadExecState.h:
(WebCore::JSMainThreadExecState::call):
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateHeader):
    - Change call to pass DOM Window shell, instead of the global varaible object.

Source/WebKit/mac: 

* Plugins/Hosted/NetscapePluginInstanceProxy.mm:
(WebKit::NetscapePluginInstanceProxy::invoke):
(WebKit::NetscapePluginInstanceProxy::invokeDefault):
    - Change call to pass DOM Window shell, instead of the global varaible object.

Source/WebKit2: 

* WebProcess/Plugins/Netscape/NPJSObject.cpp:
(WebKit::NPJSObject::invoke):
    - Change call to pass DOM Window shell, instead of the global varaible object.

LayoutTests: 

Add test case / update test results.

* fast/js/call-base-resolution-expected.txt: Added.
* fast/js/call-base-resolution.html: Added.
    - Add test for ES5 correct this value resolution in calls.
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.10_String.prototype.match/S15.5.4.10_A1_T3-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.12_String.prototype.search/S15.5.4.12_A1_T3-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.13_String.prototype.slice/S15.5.4.13_A1_T3-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.14_String.prototype.split/S15.5.4.14_A1_T3-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.15_String.prototype.substring/S15.5.4.15_A1_T3-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.4_String.prototype.charAt/S15.5.4.4_A1_T3-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.5_String.prototype.charCodeAt/S15.5.4.5_A1_T3-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.6_String.prototype.concat/S15.5.4.6_A1_T3-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.7_String.prototype.indexOf/S15.5.4.7_A1_T3-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.8_String.prototype.lastIndexOf/S15.5.4.8_A1_T3-expected.txt:
    - Check in failing results for these tests - these tests were asserting incorrect behaviour,
      and have since been fixed in test-262, see https://bugs.ecmascript.org/show_bug.cgi?id=117



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@91095 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 04f39ff2
2011-07-14 Gavin Barraclough <barraclough@apple.com>
https://bugs.webkit.org/show_bug.cgi?id=64250
Global strict mode function leaking global object as "this".
Reviewed by Oliver Hunt.
Add test case / update test results.
* fast/js/call-base-resolution-expected.txt: Added.
* fast/js/call-base-resolution.html: Added.
- Add test for ES5 correct this value resolution in calls.
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.10_String.prototype.match/S15.5.4.10_A1_T3-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.12_String.prototype.search/S15.5.4.12_A1_T3-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.13_String.prototype.slice/S15.5.4.13_A1_T3-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.14_String.prototype.split/S15.5.4.14_A1_T3-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.15_String.prototype.substring/S15.5.4.15_A1_T3-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.4_String.prototype.charAt/S15.5.4.4_A1_T3-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.5_String.prototype.charCodeAt/S15.5.4.5_A1_T3-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.6_String.prototype.concat/S15.5.4.6_A1_T3-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.7_String.prototype.indexOf/S15.5.4.7_A1_T3-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/15.5.4.8_String.prototype.lastIndexOf/S15.5.4.8_A1_T3-expected.txt:
- Check in failing results for these tests - these tests were asserting incorrect behaviour,
and have since been fixed in test-262, see https://bugs.ecmascript.org/show_bug.cgi?id=117
2011-07-15 Stephen White <senorblanco@chromium.org>
Unreviewed. Yet more chromium test baselines.
PASS ooaoboabuuaubuabooaoboab should be ooaoboabuuaubuabooaoboab, and is.
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<link rel="stylesheet" href="resources/js-test-style.css">
</head>
<body>
<p id="description"></p>
<div id="console"></div>
<script src="resources/js-test-pre.js"></script>
<script>
window.name = "o";
function f() {
return this ? this.name : "t";
}
function g() {
"use strict";
return this ? this.name : "u";
}
function h() {
return this ? this.name : "v";
}
</script>
<iframe name="i"
src="javascript:
window.f = parent.f;
window.g = parent.g;
window.a = { name:'a', f:parent.f, g:parent.g };
window.b = { name:'b', f:parent.f, g:parent.g };
Object.defineProperty(window, 'h', { get: (function(){ return parent.h; })});
Object.defineProperty(a, 'h', { get: (function(){ return parent.h; })});
Object.defineProperty(b, 'h', { get: (function(){ return parent.h; })});
var results = '';
/* Three of the first four cases pass undefined (promoted inside the callee to the callee's global object). */
/* a.f() is the one exception, which passes the base, a, as the this object. */
results += (function(){return f();})();
results += (function(){return (1,f)();})();
results += (function(){return a.f();})();
results += (function(){return eval('f()');})();
/* Same cases as above, but wrapped in a with. The first & last of these cases pass b, */
/* the object scoped by the with, as the this value. */
/* a.f() still passes the explicit base, a. (1,f)() is a little tricksier - this passes */
/* undefined (promoted to the callee global object) since teh comma operator calles GetValue */
/* on the reference (see ES5 11.14.) */
results += (function(){with(b){ return (function(){ return f();})(); }})();
results += (function(){with(b){ return (function(){ return (1,f)();})(); }})();
results += (function(){with(b){ return (function(){ return a.f();})(); }})();
results += (function(){with(b){ return (function(){ return eval('f()');})(); }})();
/* Same tests as above, but with a strict callee. */
/* We expect the same results, except undefined this is not replaced with the global object. */
results += (function(){return g();})();
results += (function(){return (1,g)();})();
results += (function(){return a.g();})();
results += (function(){return eval('g()');})();
results += (function(){with(b){ return g(); }})();
results += (function(){with(b){ return (1,g)(); }})();
results += (function(){with(b){ return a.g(); }})();
results += (function(){with(b){ return (function(){ return eval('g()');})(); }})();
/* Same as the first set, but h is a getter property. */
results += (function(){return h();})();
results += (function(){return (1,h)();})();
results += (function(){return a.h();})();
results += (function(){return eval('h()');})();
results += (function(){with(b){ return h(); }})();
results += (function(){with(b){ return (1,h)(); }})();
results += (function(){with(b){ return a.h(); }})();
results += (function(){with(b){ return (function(){ return eval('h()');})(); }})();
var expected = 'ooaoboabuuaubuabooaoboab';
if (results == expected)
parent.testPassed(results + ' should be ' + expected + ', and is.');
else
parent.testFailed(results + ' should be ' + expected + ', but was not.');
parent.successfullyParsed = true;
">
</iframe>
<script src="resources/js-test-post.js"></script>
</body>
</html>
2011-07-14 Gavin Barraclough <barraclough@apple.com>
https://bugs.webkit.org/show_bug.cgi?id=64250
Global strict mode function leaking global object as "this".
Reviewed by Oliver Hunt.
The root problem here is that we pass the wrong values into
calls, and then try to fix them up in the callee. Correct
behaviour per the spec is to pass in the value undefined,
as this unless either (1) the function call is based on an
explicit property access or (2) the base of the call comes
directly from a 'with'.
This change does away with the need for this conversion of
objects (non strict code should only box primitives), and
does away with all this conversion for strict functions.
This patch may have web compatibility ramifications, and may
require some advocacy.
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dump):
- Removed op_convert_this_strict, added op_resolve_with_this.
* bytecode/Opcode.h:
- Removed op_convert_this_strict, added op_resolve_with_this.
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitResolveWithThis):
- Removed op_convert_this_strict, added op_resolve_with_this.
* bytecompiler/BytecodeGenerator.h:
- Removed op_convert_this_strict, added op_resolve_with_this.
* bytecompiler/NodesCodegen.cpp:
(JSC::EvalFunctionCallNode::emitBytecode):
(JSC::FunctionCallResolveNode::emitBytecode):
- Removed op_convert_this_strict, added op_resolve_with_this.
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compile):
- Change NeedsThisConversion check to test for JSString's vptr
(objects no longer need conversion).
* interpreter/Interpreter.cpp:
(JSC::Interpreter::resolveThisAndProperty):
- Based on resolveBaseAndProperty, but produce correct this value.
(JSC::Interpreter::privateExecute):
- Removed op_convert_this_strict, added op_resolve_with_this.
* interpreter/Interpreter.h:
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
- Removed op_convert_this_strict, added op_resolve_with_this.
* jit/JIT.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_resolve_with_this):
- Removed op_convert_this_strict, added op_resolve_with_this.
(JSC::JIT::emit_op_convert_this):
(JSC::JIT::emitSlow_op_convert_this):
- Change NeedsThisConversion check to test for JSString's vptr
(objects no longer need conversion).
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_resolve_with_this):
- Removed op_convert_this_strict, added op_resolve_with_this.
(JSC::JIT::emit_op_convert_this):
(JSC::JIT::emitSlow_op_convert_this):
- Change NeedsThisConversion check to test for JSString's vptr
(objects no longer need conversion).
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
- Removed op_convert_this_strict, added op_resolve_with_this.
* jit/JITStubs.h:
- Removed op_convert_this_strict, added op_resolve_with_this.
* runtime/JSActivation.h:
- removed NeedsThisConversion flag, added IsEnvironmentRecord.
* runtime/JSStaticScopeObject.h:
- removed NeedsThisConversion flag, added IsEnvironmentRecord.
* runtime/JSString.h:
(JSC::RopeBuilder::createStructure):
- removed NeedsThisConversion.
* runtime/JSTypeInfo.h:
(JSC::TypeInfo::isEnvironmentRecord):
(JSC::TypeInfo::overridesHasInstance):
- removed NeedsThisConversion flag, added IsEnvironmentRecord.
* runtime/JSValue.h:
- removed NeedsThisConversion.
* runtime/JSVariableObject.h:
- Corrected StructureFlags inheritance.
* runtime/StrictEvalActivation.h:
(JSC::StrictEvalActivation::createStructure):
- Added IsEnvironmentRecord to StructureFlags, addded createStructure.
* runtime/Structure.h:
- removed NeedsThisConversion.
* tests/mozilla/ecma/String/15.5.4.6-2.js:
(getTestCases):
- Removed invalid test case.
2011-07-15 Sheriff Bot <webkit.review.bot@gmail.com>
Unreviewed, rolling out r91082, r91087, and r91089.
......
......@@ -522,11 +522,6 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
printf("[%4d] convert_this %s\n", location, registerName(exec, r0).data());
break;
}
case op_convert_this_strict: {
int r0 = (++it)->u.operand;
printf("[%4d] convert_this_strict %s\n", location, registerName(exec, r0).data());
break;
}
case op_new_object: {
int r0 = (++it)->u.operand;
printf("[%4d] new_object\t %s\n", location, registerName(exec, r0).data());
......@@ -803,6 +798,13 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
printf("[%4d] resolve_with_base %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data());
break;
}
case op_resolve_with_this: {
int r0 = (++it)->u.operand;
int r1 = (++it)->u.operand;
int id0 = (++it)->u.operand;
printf("[%4d] resolve_with_this %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data());
break;
}
case op_get_by_id: {
printGetByIdOp(exec, location, it, "get_by_id");
break;
......
......@@ -45,7 +45,6 @@ namespace JSC {
macro(op_create_this, 3) \
macro(op_get_callee, 2) \
macro(op_convert_this, 2) \
macro(op_convert_this_strict, 2) \
\
macro(op_new_object, 2) \
macro(op_new_array, 4) \
......@@ -107,6 +106,7 @@ namespace JSC {
macro(op_resolve_base, 4) \
macro(op_ensure_property_exists, 3) \
macro(op_resolve_with_base, 4) \
macro(op_resolve_with_this, 4) \
macro(op_get_by_id, 8) \
macro(op_get_by_id_self, 8) \
macro(op_get_by_id_self_list, 8) \
......
......@@ -414,11 +414,10 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, ScopeChainN
instructions().append(m_thisRegister.index());
instructions().append(funcProto->index());
} else if (functionBody->usesThis() || m_shouldEmitDebugHooks) {
if (codeBlock->isStrictMode())
emitOpcode(op_convert_this_strict);
else
if (!codeBlock->isStrictMode()) {
emitOpcode(op_convert_this);
instructions().append(m_thisRegister.index());
instructions().append(m_thisRegister.index());
}
}
}
......@@ -1415,6 +1414,53 @@ RegisterID* BytecodeGenerator::emitResolveWithBase(RegisterID* baseDst, Register
return baseDst;
}
RegisterID* BytecodeGenerator::emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const Identifier& property)
{
size_t depth = 0;
int index = 0;
JSObject* globalObject = 0;
bool requiresDynamicChecks = false;
if (!findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject) || !globalObject || requiresDynamicChecks) {
// We can't optimise at all :-(
emitOpcode(op_resolve_with_this);
instructions().append(baseDst->index());
instructions().append(propDst->index());
instructions().append(addConstant(property));
return baseDst;
}
bool forceGlobalResolve = false;
// Global object is the base
emitLoad(baseDst, jsUndefined());
if (index != missingSymbolMarker() && !forceGlobalResolve) {
// Directly index the property lookup across multiple scopes.
emitGetScopedVar(propDst, depth, index, globalObject);
return baseDst;
}
if (shouldAvoidResolveGlobal()) {
emitOpcode(op_resolve);
instructions().append(propDst->index());
instructions().append(addConstant(property));
return baseDst;
}
#if ENABLE(JIT)
m_codeBlock->addGlobalResolveInfo(instructions().size());
#endif
#if ENABLE(INTERPRETER)
m_codeBlock->addGlobalResolveInstruction(instructions().size());
#endif
emitOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global);
instructions().append(propDst->index());
instructions().append(addConstant(property));
instructions().append(0);
instructions().append(0);
if (requiresDynamicChecks)
instructions().append(depth);
return baseDst;
}
void BytecodeGenerator::emitMethodCheck()
{
emitOpcode(op_method_check);
......
......@@ -313,6 +313,7 @@ namespace JSC {
RegisterID* emitResolveBase(RegisterID* dst, const Identifier& property);
RegisterID* emitResolveBaseForPut(RegisterID* dst, const Identifier& property);
RegisterID* emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property);
RegisterID* emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const Identifier& property);
void emitMethodCheck();
......
......@@ -335,7 +335,7 @@ RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, Reg
RefPtr<RegisterID> func = generator.tempDestination(dst);
CallArguments callArguments(generator, m_args);
generator.emitExpressionInfo(divot() - startOffset() + 4, 4, 0);
generator.emitResolveWithBase(callArguments.thisRegister(), func.get(), generator.propertyNames().eval);
generator.emitResolveWithThis(callArguments.thisRegister(), func.get(), generator.propertyNames().eval);
return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset());
}
......@@ -374,7 +374,7 @@ RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator,
CallArguments callArguments(generator, m_args);
int identifierStart = divot() - startOffset();
generator.emitExpressionInfo(identifierStart + m_ident.length(), m_ident.length(), 0);
generator.emitResolveWithBase(callArguments.thisRegister(), func.get(), m_ident);
generator.emitResolveWithThis(callArguments.thisRegister(), func.get(), m_ident);
return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset());
}
......
......@@ -975,10 +975,8 @@ void SpeculativeJIT::compile(Node& node)
case ConvertThis: {
SpeculateCellOperand thisValue(this, node.child1());
GPRTemporary temp(this);
m_jit.loadPtr(JITCompiler::Address(thisValue.gpr(), JSCell::structureOffset()), temp.gpr());
speculationCheck(m_jit.branchTest8(JITCompiler::NonZero, JITCompiler::Address(temp.gpr(), Structure::typeInfoFlagsOffset()), JITCompiler::TrustedImm32(NeedsThisConversion)));
speculationCheck(m_jit.branchPtr(JITCompiler::Equal, JITCompiler::Address(thisValue.gpr()), JITCompiler::TrustedImmPtr(m_jit.globalData()->jsStringVPtr)));
cellResult(thisValue.gpr(), m_compileIndex);
break;
......
......@@ -321,6 +321,50 @@ NEVER_INLINE bool Interpreter::resolveBaseAndProperty(CallFrame* callFrame, Inst
return false;
}
NEVER_INLINE bool Interpreter::resolveThisAndProperty(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
{
int thisDst = vPC[1].u.operand;
int propDst = vPC[2].u.operand;
int property = vPC[3].u.operand;
ScopeChainNode* scopeChain = callFrame->scopeChain();
ScopeChainIterator iter = scopeChain->begin();
ScopeChainIterator end = scopeChain->end();
// FIXME: add scopeDepthIsZero optimization
ASSERT(iter != end);
CodeBlock* codeBlock = callFrame->codeBlock();
Identifier& ident = codeBlock->identifier(property);
JSObject* base;
do {
base = iter->get();
++iter;
PropertySlot slot(base);
if (base->getPropertySlot(callFrame, ident, slot)) {
JSValue result = slot.getValue(callFrame, ident);
exceptionValue = callFrame->globalData().exception;
if (exceptionValue)
return false;
callFrame->uncheckedR(propDst) = JSValue(result);
// All entries on the scope chain should be EnvironmentRecords (activations etc),
// other then 'with' object, which are directly referenced from the scope chain,
// and the global object. If we hit either an EnvironmentRecord or a global
// object at the end of the scope chain, this is undefined. If we hit a non-
// EnvironmentRecord within the scope chain, pass the base as the this value.
if (iter == end || base->structure()->typeInfo().isEnvironmentRecord())
callFrame->uncheckedR(thisDst) = jsUndefined();
else
callFrame->uncheckedR(thisDst) = JSValue(base);
return true;
}
} while (iter != end);
exceptionValue = createUndefinedVariableError(callFrame, ident);
return false;
}
#endif // ENABLE(INTERPRETER)
ALWAYS_INLINE CallFrame* Interpreter::slideRegisterWindowForCall(CodeBlock* newCodeBlock, RegisterFile* registerFile, CallFrame* callFrame, size_t registerOffset, int argc)
......@@ -409,7 +453,9 @@ NEVER_INLINE JSValue Interpreter::callEval(CallFrame* callFrame, RegisterFile* r
if (UNLIKELY(!eval))
return throwError(callFrame, exceptionValue);
return callFrame->globalData().interpreter->execute(eval, callFrame, callFrame->uncheckedR(codeBlock->thisRegister()).jsValue().toThisObject(callFrame), callFrame->registers() - registerFile->begin() + registerOffset, scopeChain);
JSValue thisValue = callFrame->uncheckedR(codeBlock->thisRegister()).jsValue();
ASSERT(isValidThisObject(thisValue, callFrame));
return callFrame->globalData().interpreter->execute(eval, callFrame, thisValue, callFrame->registers() - registerFile->begin() + registerOffset, scopeChain);
}
Interpreter::Interpreter()
......@@ -718,6 +764,7 @@ static inline JSObject* checkedReturn(JSObject* returnValue)
JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj)
{
ASSERT(isValidThisObject(thisObj, callFrame));
ASSERT(!scopeChain->globalData->exception);
ASSERT(!callFrame->globalData().isCollectorBusy());
if (callFrame->globalData().isCollectorBusy())
......@@ -843,6 +890,7 @@ failedJSONP:
JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args)
{
ASSERT(isValidThisObject(thisValue, callFrame));
ASSERT(!callFrame->hadException());
ASSERT(!callFrame->globalData().isCollectorBusy());
if (callFrame->globalData().isCollectorBusy())
......@@ -1118,16 +1166,17 @@ void Interpreter::endRepeatCall(CallFrameClosure& closure)
m_registerFile.shrink(closure.oldEnd);
}
JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, ScopeChainNode* scopeChain)
JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue thisValue, ScopeChainNode* scopeChain)
{
JSObject* compileError = eval->compile(callFrame, scopeChain);
if (UNLIKELY(!!compileError))
return checkedReturn(throwError(callFrame, compileError));
return execute(eval, callFrame, thisObj, m_registerFile.size() + eval->generatedBytecode().m_numParameters + RegisterFile::CallFrameHeaderSize, scopeChain);
return execute(eval, callFrame, thisValue, m_registerFile.size() + eval->generatedBytecode().m_numParameters + RegisterFile::CallFrameHeaderSize, scopeChain);
}
JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, int globalRegisterOffset, ScopeChainNode* scopeChain)
JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue thisValue, int globalRegisterOffset, ScopeChainNode* scopeChain)
{
ASSERT(isValidThisObject(thisValue, callFrame));
ASSERT(!scopeChain->globalData->exception);
ASSERT(!callFrame->globalData().isCollectorBusy());
if (callFrame->globalData().isCollectorBusy())
......@@ -1191,7 +1240,7 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObjec
ASSERT(codeBlock->m_numParameters == 1); // 1 parameter for 'this'.
newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), codeBlock->m_numParameters, 0);
newCallFrame->uncheckedR(newCallFrame->hostThisRegister()) = JSValue(thisObj);
newCallFrame->uncheckedR(newCallFrame->hostThisRegister()) = thisValue.toThisObject(newCallFrame);
Profiler** profiler = Profiler::enabledProfilerReference();
if (*profiler)
......@@ -2604,6 +2653,22 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi
vPC += OPCODE_LENGTH(op_resolve_with_base);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_resolve_with_this) {
/* resolve_with_this thisDst(r) propDst(r) property(id)
Searches the scope chain for an object containing
identifier property, and if one is found, writes the
retrieved property value to register propDst, and the
this object to pass in a call to thisDst.
If the property is not found, raises an exception.
*/
if (UNLIKELY(!resolveThisAndProperty(callFrame, vPC, exceptionValue)))
goto vm_throw;
vPC += OPCODE_LENGTH(op_resolve_with_this);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_get_by_id) {
/* get_by_id dst(r) base(r) property(id) structure(sID) nop(n) nop(n) nop(n)
......@@ -4556,31 +4621,12 @@ skip_id_custom_self:
int thisRegister = vPC[1].u.operand;
JSValue thisVal = callFrame->r(thisRegister).jsValue();
if (thisVal.needsThisConversion())
if (!thisVal.isCell() || thisVal.isString())
callFrame->uncheckedR(thisRegister) = JSValue(thisVal.toThisObject(callFrame));
vPC += OPCODE_LENGTH(op_convert_this);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(op_convert_this_strict) {