+2008-07-25 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Cameron Zwarich.
+
+ Bug 19718: Named anonymous functions are slow accessing global variables
+ <https://bugs.webkit.org/show_bug.cgi?id=19718>
+
+ To fix this we switch over to an activation-like scope object for
+ on which we attach the function name property, and add logic to
+ prevent cross scope assignment to read only properties.
+
+ * GNUmakefile.am:
+ * JavaScriptCore.pri:
+ * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * VM/CodeGenerator.cpp:
+ (KJS::CodeGenerator::findScopedProperty):
+ (KJS::CodeGenerator::emitResolve):
+ * VM/CodeGenerator.h:
+ * kjs/AllInOneFile.cpp:
+ * kjs/JSStaticScopeObject.cpp: Added.
+ (KJS::JSStaticScopeObject::putWithAttributes):
+ (KJS::JSStaticScopeObject::isDynamicScope):
+ (KJS::JSStaticScopeObject::~JSStaticScopeObject):
+ (KJS::JSStaticScopeObject::getOwnPropertySlot):
+ * kjs/JSStaticScopeObject.h: Added.
+ (KJS::JSStaticScopeObject::JSStaticScopeObjectData::JSStaticScopeObjectData):
+ (KJS::JSStaticScopeObject::JSStaticScopeObject):
+ * kjs/nodes.cpp:
+ (KJS::FunctionCallResolveNode::emitCode):
+ (KJS::PostfixResolveNode::emitCode):
+ (KJS::PrefixResolveNode::emitCode):
+ (KJS::ReadModifyResolveNode::emitCode):
+ (KJS::AssignResolveNode::emitCode):
+ (KJS::FuncExprNode::makeFunction):
+
2008-07-25 kevino <kevino@theolliviers.com>
wx build fix for Win.
JavaScriptCore/kjs/JSLock.cpp \
JavaScriptCore/kjs/JSNumberCell.cpp \
JavaScriptCore/kjs/JSObject.cpp \
+ JavaScriptCore/kjs/JSStaticScopeObject.cpp \
JavaScriptCore/kjs/JSString.cpp \
JavaScriptCore/kjs/JSValue.cpp \
JavaScriptCore/kjs/JSVariableObject.cpp \
kjs/InitializeThreading.cpp \
kjs/JSGlobalData.cpp \
kjs/JSGlobalObject.cpp \
+ kjs/JSStaticScopeObject.cpp \
kjs/JSVariableObject.cpp \
kjs/JSActivation.cpp \
kjs/JSNotAnObject.cpp \
>\r
</File>\r
<File\r
+ RelativePath="..\..\kjs\JSStaticScopeObject.cpp"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath="..\..\kjs\JSStaticScopeObject.h"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath="..\..\kjs\JSGlobalObjectFunctions.cpp"\r
>\r
</File>\r
A727FF650DA3053B00E548D7 /* JSPropertyNameIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSPropertyNameIterator.h; path = VM/JSPropertyNameIterator.h; sourceTree = "<group>"; };
A727FF660DA3053B00E548D7 /* JSPropertyNameIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JSPropertyNameIterator.cpp; path = VM/JSPropertyNameIterator.cpp; sourceTree = "<group>"; };
A7C31DA80DBEBA4300FDF8EB /* SegmentedVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SegmentedVector.h; path = VM/SegmentedVector.h; sourceTree = "<group>"; };
+ A7E42C180E3938830065A544 /* JSStaticScopeObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSStaticScopeObject.h; sourceTree = "<group>"; };
+ A7E42C190E3938830065A544 /* JSStaticScopeObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSStaticScopeObject.cpp; sourceTree = "<group>"; };
A8E894310CD0602400367179 /* JSCallbackObjectFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCallbackObjectFunctions.h; sourceTree = "<group>"; };
A8E894330CD0603F00367179 /* JSGlobalObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGlobalObject.h; sourceTree = "<group>"; };
BC02E9040E1839DB000F9297 /* ErrorConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ErrorConstructor.cpp; sourceTree = "<group>"; };
BC7F8FB80E19D1C3008632C0 /* JSNumberCell.h */,
BC22A3980E16E14800AF21C8 /* JSObject.cpp */,
BC22A3990E16E14800AF21C8 /* JSObject.h */,
+ A7E42C180E3938830065A544 /* JSStaticScopeObject.h */,
+ A7E42C190E3938830065A544 /* JSStaticScopeObject.cpp */,
BC02E9B60E1842FA000F9297 /* JSString.cpp */,
F692A8620255597D01FF60F7 /* JSString.h */,
14ABB454099C2A0F00E2A24F /* JSType.h */,
return dst;
}
-bool CodeGenerator::findScopedProperty(const Identifier& property, int& index, size_t& stackDepth)
+bool CodeGenerator::findScopedProperty(const Identifier& property, int& index, size_t& stackDepth, bool forWriting)
{
// Cases where we cannot optimise the lookup
if (property == propertyNames().arguments || !canOptimizeNonLocals()) {
// Found the property
if (!entry.isNull()) {
+ if (entry.isReadOnly() && forWriting) {
+ stackDepth = 0;
+ index = missingSymbolMarker();
+ return false;
+ }
stackDepth = depth;
index = entry.getIndex();
return true;
{
size_t depth = 0;
int index = 0;
- if (!findScopedProperty(property, index, depth)) {
+ if (!findScopedProperty(property, index, depth, false)) {
// We can't optimise at all :-(
emitOpcode(op_resolve);
instructions().append(dst->index());
//
// NB: depth does _not_ include the local scope. eg. a depth of 0 refers
// to the scope containing this codeblock.
- bool findScopedProperty(const Identifier&, int& index, size_t& depth);
+ bool findScopedProperty(const Identifier&, int& index, size_t& depth, bool forWriting);
// Returns the register storing "this"
RegisterID* thisRegister() { return &m_thisRegister; }
#define JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE 1
#include "config.h"
+#include "JSStaticScopeObject.cpp"
#include "JSFunction.cpp"
#include "IndexToNameMap.cpp"
#include "Arguments.cpp"
--- /dev/null
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "JSStaticScopeObject.h"
+
+namespace KJS {
+
+void JSStaticScopeObject::putWithAttributes(ExecState*, const Identifier& propertyName, JSValue* value, unsigned attributes)
+{
+ if (symbolTablePutWithAttributes(propertyName, value, attributes))
+ return;
+
+ ASSERT_NOT_REACHED();
+}
+
+bool JSStaticScopeObject::isDynamicScope() const
+{
+ return false;
+}
+
+JSStaticScopeObject::~JSStaticScopeObject()
+{
+ ASSERT(d);
+ delete static_cast<JSStaticScopeObjectData*>(d);
+}
+
+inline bool JSStaticScopeObject::getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot& slot)
+{
+ return symbolTableGet(propertyName, slot);
+}
+
+inline bool JSStaticScopeObject::getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot& slot, bool& slotIsWriteable)
+{
+ return symbolTableGet(propertyName, slot, slotIsWriteable);
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSStaticScopeObject_h
+#define JSStaticScopeObject_h
+
+#include "JSVariableObject.h"
+
+namespace KJS{
+
+ class JSStaticScopeObject : public JSVariableObject {
+ protected:
+ using JSVariableObject::JSVariableObjectData;
+ struct JSStaticScopeObjectData : public JSVariableObjectData {
+ JSStaticScopeObjectData()
+ : JSVariableObjectData(&symbolTable, ®isterStore + 1)
+ {
+ registerArraySize = 1;
+ }
+ SymbolTable symbolTable;
+ Register registerStore;
+ };
+
+ public:
+ JSStaticScopeObject(const Identifier& ident, JSValue* value, unsigned attributes)
+ : JSVariableObject(new JSStaticScopeObjectData())
+ {
+ JSStaticScopeObjectData* data = static_cast<JSStaticScopeObjectData*>(d);
+ data->registerStore = value;
+ symbolTable().add(ident.ustring().rep(), SymbolTableEntry(-1, attributes));
+ }
+ virtual ~JSStaticScopeObject();
+ bool isDynamicScope() const;
+ virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
+ virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&, bool& slotIsWriteable);
+ void putWithAttributes(ExecState*, const Identifier&, JSValue*, unsigned attributes);
+ };
+
+}
+
+#endif // !JSStaticScopeObject_h
#include "CodeGenerator.h"
#include "ExecState.h"
#include "JSGlobalObject.h"
+#include "JSStaticScopeObject.h"
#include "Parser.h"
#include "PropertyNameArray.h"
#include "RegExpObject.h"
int index = 0;
size_t depth = 0;
- if (generator.findScopedProperty(m_ident, index, depth) && index != missingSymbolMarker()) {
+ if (generator.findScopedProperty(m_ident, index, depth, false) && index != missingSymbolMarker()) {
RegisterID* func = generator.emitGetScopedVar(generator.newTemporary(), depth, index);
return generator.emitCall(generator.finalDestination(dst), func, 0, m_args.get(), m_divot, m_startOffset, m_endOffset);
}
int index = 0;
size_t depth = 0;
- if (generator.findScopedProperty(m_ident, index, depth) && index != missingSymbolMarker()) {
+ if (generator.findScopedProperty(m_ident, index, depth, true) && index != missingSymbolMarker()) {
RefPtr<RegisterID> value = generator.emitGetScopedVar(generator.newTemporary(), depth, index);
RegisterID* oldValue;
if (dst == ignoredResult()) {
int index = 0;
size_t depth = 0;
- if (generator.findScopedProperty(m_ident, index, depth) && index != missingSymbolMarker()) {
+ if (generator.findScopedProperty(m_ident, index, depth, false) && index != missingSymbolMarker()) {
RefPtr<RegisterID> propDst = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index);
emitPreIncOrDec(generator, propDst.get(), m_operator);
generator.emitPutScopedVar(depth, index, propDst.get());
int index = 0;
size_t depth = 0;
- if (generator.findScopedProperty(m_ident, index, depth) && index != missingSymbolMarker()) {
+ if (generator.findScopedProperty(m_ident, index, depth, true) && index != missingSymbolMarker()) {
RefPtr<RegisterID> src1 = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index);
RegisterID* src2 = generator.emitNode(m_right.get());
RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), src2, m_operator);
int index = 0;
size_t depth = 0;
- if (generator.findScopedProperty(m_ident, index, depth) && index != missingSymbolMarker()) {
+ if (generator.findScopedProperty(m_ident, index, depth, true) && index != missingSymbolMarker()) {
if (dst == ignoredResult())
dst = 0;
RegisterID* value = generator.emitNode(dst, m_right.get());
*/
if (!m_ident.isNull()) {
- JSObject* functionScopeObject = new (exec) JSObject;
- functionScopeObject->putDirect(m_ident, func, ReadOnly | DontDelete);
+ JSStaticScopeObject* functionScopeObject = new (exec) JSStaticScopeObject(m_ident, func, ReadOnly | DontDelete);
func->scope().push(functionScopeObject);
}
+2008-07-25 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Cameron Zwarich.
+
+ Layout test covering assignment to read only properties
+ across scope boundaries.
+
+ * fast/js/const-expected.txt:
+ * fast/js/resources/const.js:
+
2008-07-25 Dan Bernstein <mitz@apple.com>
Rubber-stamped by Sam Weinig.
PASS one is 1
PASS object.inWith1 is 'RIGHT'
PASS inWith2 is 'RIGHT'
+PASS (function(){ one = 2; return one; })() is 1
+PASS f() is f
PASS successfullyParsed is true
TEST COMPLETE
shouldBe("object.inWith1", "'RIGHT'");
shouldBe("inWith2", "'RIGHT'");
+shouldBe("(function(){ one = 2; return one; })()", "1")
+var f = function g() { g="FAIL"; return g; };
+shouldBe("f()", "f");
+
var successfullyParsed = true;