JavaScriptCore:
authormjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 4 Oct 2008 07:15:33 +0000 (07:15 +0000)
committermjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 4 Oct 2008 07:15:33 +0000 (07:15 +0000)
2008-10-03  Maciej Stachowiak  <mjs@apple.com>

        Reviewed by Cameron Zwarich.

        - "this" object in methods called on primitives should be wrapper object
        https://bugs.webkit.org/show_bug.cgi?id=21362

        I changed things so that functions which use "this" do a fast
        version of toThisObject conversion if needed. Currently we miss
        the conversion entirely, at least for primitive types. Using
        TypeInfo and the primitive check, I made the fast case bail out
        pretty fast.

        This is inexplicably an 1.007x SunSpider speedup (and a wash on V8 benchmarks).

        Also renamed some opcodes for clarity:

        init ==> enter
        init_activation ==> enter_with_activation

        * VM/CTI.cpp:
        (JSC::CTI::privateCompileMainPass):
        (JSC::CTI::privateCompileSlowCases):
        * VM/CodeBlock.cpp:
        (JSC::CodeBlock::dump):
        * VM/CodeGenerator.cpp:
        (JSC::CodeGenerator::generate):
        (JSC::CodeGenerator::CodeGenerator):
        * VM/Machine.cpp:
        (JSC::Machine::privateExecute):
        (JSC::Machine::cti_op_convert_this):
        * VM/Machine.h:
        * VM/Opcode.h:
        * kjs/JSActivation.cpp:
        (JSC::JSActivation::JSActivation):
        * kjs/JSActivation.h:
        (JSC::JSActivation::createStructureID):
        * kjs/JSCell.h:
        (JSC::JSValue::needsThisConversion):
        * kjs/JSGlobalData.cpp:
        (JSC::JSGlobalData::JSGlobalData):
        * kjs/JSGlobalData.h:
        * kjs/JSNumberCell.h:
        (JSC::JSNumberCell::createStructureID):
        * kjs/JSStaticScopeObject.h:
        (JSC::JSStaticScopeObject::JSStaticScopeObject):
        (JSC::JSStaticScopeObject::createStructureID):
        * kjs/JSString.h:
        (JSC::JSString::createStructureID):
        * kjs/JSValue.h:
        * kjs/TypeInfo.h:
        (JSC::TypeInfo::needsThisConversion):
        * kjs/nodes.h:
        (JSC::ScopeNode::usesThis):

WebCore:

2008-10-03  Maciej Stachowiak  <mjs@apple.com>

        Reviewed by Cameron Zwarich.

        - "this" object in methods called on primitives should be wrapper object
        https://bugs.webkit.org/show_bug.cgi?id=21362

        Updated so toThis conversion for the split window is handled properly.

        * bindings/scripts/CodeGeneratorJS.pm:

LayoutTests:

2008-10-03  Maciej Stachowiak  <mjs@apple.com>

        Reviewed by Cameron Zwarich.

        - test case for: "this" object in methods called on primitives should be wrapper object

        * fast/js/primitive-method-this-expected.txt: Added.
        * fast/js/primitive-method-this.html: Added.
        * fast/js/resources/primitive-method-this.js: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@37285 268f45cc-cd09-0410-ab3c-d52691b4dbfc

24 files changed:
JavaScriptCore/ChangeLog
JavaScriptCore/VM/CTI.cpp
JavaScriptCore/VM/CodeBlock.cpp
JavaScriptCore/VM/CodeGenerator.cpp
JavaScriptCore/VM/Machine.cpp
JavaScriptCore/VM/Machine.h
JavaScriptCore/VM/Opcode.h
JavaScriptCore/kjs/JSActivation.cpp
JavaScriptCore/kjs/JSActivation.h
JavaScriptCore/kjs/JSCell.h
JavaScriptCore/kjs/JSGlobalData.cpp
JavaScriptCore/kjs/JSGlobalData.h
JavaScriptCore/kjs/JSNumberCell.h
JavaScriptCore/kjs/JSStaticScopeObject.h
JavaScriptCore/kjs/JSString.h
JavaScriptCore/kjs/JSValue.h
JavaScriptCore/kjs/TypeInfo.h
JavaScriptCore/kjs/nodes.h
LayoutTests/ChangeLog
LayoutTests/fast/js/primitive-method-this-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/primitive-method-this.html [new file with mode: 0644]
LayoutTests/fast/js/resources/primitive-method-this.js [new file with mode: 0644]
WebCore/ChangeLog
WebCore/bindings/scripts/CodeGeneratorJS.pm

index c8dea35faf2f34fe0585c6fc058f1699b541929f..9dc019a8656f1a38477bcdc7b3db1ce0f37a729e 100644 (file)
@@ -1,3 +1,58 @@
+2008-10-03  Maciej Stachowiak  <mjs@apple.com>
+
+        Reviewed by Cameron Zwarich.
+        
+        - "this" object in methods called on primitives should be wrapper object
+        https://bugs.webkit.org/show_bug.cgi?id=21362
+
+        I changed things so that functions which use "this" do a fast
+        version of toThisObject conversion if needed. Currently we miss
+        the conversion entirely, at least for primitive types. Using
+        TypeInfo and the primitive check, I made the fast case bail out
+        pretty fast.
+        
+        This is inexplicably an 1.007x SunSpider speedup (and a wash on V8 benchmarks).
+     
+        Also renamed some opcodes for clarity:
+        
+        init ==> enter
+        init_activation ==> enter_with_activation
+        
+        * VM/CTI.cpp:
+        (JSC::CTI::privateCompileMainPass):
+        (JSC::CTI::privateCompileSlowCases):
+        * VM/CodeBlock.cpp:
+        (JSC::CodeBlock::dump):
+        * VM/CodeGenerator.cpp:
+        (JSC::CodeGenerator::generate):
+        (JSC::CodeGenerator::CodeGenerator):
+        * VM/Machine.cpp:
+        (JSC::Machine::privateExecute):
+        (JSC::Machine::cti_op_convert_this):
+        * VM/Machine.h:
+        * VM/Opcode.h:
+        * kjs/JSActivation.cpp:
+        (JSC::JSActivation::JSActivation):
+        * kjs/JSActivation.h:
+        (JSC::JSActivation::createStructureID):
+        * kjs/JSCell.h:
+        (JSC::JSValue::needsThisConversion):
+        * kjs/JSGlobalData.cpp:
+        (JSC::JSGlobalData::JSGlobalData):
+        * kjs/JSGlobalData.h:
+        * kjs/JSNumberCell.h:
+        (JSC::JSNumberCell::createStructureID):
+        * kjs/JSStaticScopeObject.h:
+        (JSC::JSStaticScopeObject::JSStaticScopeObject):
+        (JSC::JSStaticScopeObject::createStructureID):
+        * kjs/JSString.h:
+        (JSC::JSString::createStructureID):
+        * kjs/JSValue.h:
+        * kjs/TypeInfo.h:
+        (JSC::TypeInfo::needsThisConversion):
+        * kjs/nodes.h:
+        (JSC::ScopeNode::usesThis):
+
 2008-10-03  Cameron Zwarich  <zwarich@apple.com>
 
         Reviewed by Maciej Stachowiak.
index 7cb71066b0faeb45d54895c599df530ff132f4d0..3702946f3a3d568694d779fbc9745abd3abdd07f 100644 (file)
@@ -1964,7 +1964,7 @@ void CTI::privateCompileMainPass()
             i += 3;
             break;
         }
-        case op_init: {
+        case op_enter: {
             // Even though CTI doesn't use them, we initialize our constant
             // registers to zap stale pointers, to avoid unnecessarily prolonging
             // object lifetime and increasing GC pressure.
@@ -1975,7 +1975,7 @@ void CTI::privateCompileMainPass()
             i+= 1;
             break;
         }
-        case op_init_activation: {
+        case op_enter_with_activation: {
             emitCall(i, Machine::cti_op_push_activation);
 
             // Even though CTI doesn't use them, we initialize our constant
@@ -1993,6 +1993,17 @@ void CTI::privateCompileMainPass()
             i += 1;
             break;
         }
+        case op_convert_this: {
+            emitGetArg(instruction[i + 1].u.operand, X86::eax);
+
+            emitJumpSlowCaseIfNotJSCell(X86::eax, i);
+            m_jit.movl_mr(OBJECT_OFFSET(JSCell, m_structureID), X86::eax, X86::edx);
+            m_jit.testl_i32m(NeedsThisConversion, OBJECT_OFFSET(StructureID, m_typeInfo.m_flags), X86::edx);
+            m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJnz(), i));
+
+            i += 2;
+            break;
+        }
         case op_get_array_length:
         case op_get_by_id_chain:
         case op_get_by_id_generic:
@@ -2037,6 +2048,15 @@ void CTI::privateCompileSlowCases()
     for (Vector<SlowCaseEntry>::iterator iter = m_slowCases.begin(); iter != m_slowCases.end(); ++iter) {
         unsigned i = iter->to;
         switch (m_machine->getOpcodeID(instruction[i].u.opcode)) {
+        case op_convert_this: {
+            m_jit.link(iter->from, m_jit.label());
+            m_jit.link((++iter)->from, m_jit.label());
+            emitPutArg(X86::eax, 0);
+            emitCall(i, Machine::cti_op_convert_this);
+            emitPutResult(instruction[i + 1].u.operand);
+            i += 2;
+            break;
+        }
         case op_add: {
             unsigned dst = instruction[i + 1].u.operand;
             unsigned src1 = instruction[i + 2].u.operand;
index eaf94e291702f61ec01b6c8a8558977c53b110fa..dc17fc16ae8df26873250eeddf411e21aac08220 100644 (file)
@@ -348,18 +348,23 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
 {
     int location = it - begin;
     switch (exec->machine()->getOpcodeID(it->u.opcode)) {
-        case op_init: {
-            printf("[%4d] init\n", location);
+        case op_enter: {
+            printf("[%4d] enter\n", location);
             break;
         }
-        case op_init_activation: {
-            printf("[%4d] init_activation\n", location);
+        case op_enter_with_activation: {
+            printf("[%4d] enter_with_activation\n", location);
             break;
         }
         case op_init_arguments: {
             printf("[%4d] init_arguments\n", location);
             break;
         }
+        case op_convert_this: {
+            int r0 = (++it)->u.operand;
+            printf("[%4d] convert_this %s\n", location, registerName(r0).c_str());
+            break;
+        }
         case op_unexpected_load: {
             int r0 = (++it)->u.operand;
             int k0 = (++it)->u.operand;
index 0234a74af0ccf0a756999a76eee3e92d3a440d38..bb395921149c190de308276c68b886ee1a753bf9 100644 (file)
@@ -137,8 +137,8 @@ void CodeGenerator::generate()
     m_scopeNode->emitCode(*this);
 
     if (m_codeType == FunctionCode && m_codeBlock->needsFullScopeChain) {
-        ASSERT(globalData()->machine->getOpcodeID(m_codeBlock->instructions[0].u.opcode) == op_init);
-        m_codeBlock->instructions[0] = globalData()->machine->getOpcode(op_init_activation);
+        ASSERT(globalData()->machine->getOpcodeID(m_codeBlock->instructions[0].u.opcode) == op_enter);
+        m_codeBlock->instructions[0] = globalData()->machine->getOpcode(op_enter_with_activation);
     }
 
 #ifndef NDEBUG
@@ -216,7 +216,7 @@ CodeGenerator::CodeGenerator(ProgramNode* programNode, const Debugger* debugger,
     , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
     , m_lastOpcodeID(op_end)
 {
-    emitOpcode(op_init);
+    emitOpcode(op_enter);
     codeBlock->globalData = m_globalData;
 
     // FIXME: Move code that modifies the global object to Machine::execute.
@@ -289,7 +289,7 @@ CodeGenerator::CodeGenerator(FunctionBodyNode* functionBody, const Debugger* deb
     , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
     , m_lastOpcodeID(op_end)
 {
-    emitOpcode(op_init);
+    emitOpcode(op_enter);
     codeBlock->globalData = m_globalData;
 
     bool usesArguments = functionBody->usesArguments();
@@ -321,6 +321,11 @@ CodeGenerator::CodeGenerator(FunctionBodyNode* functionBody, const Debugger* deb
     m_thisRegister.setIndex(m_nextParameter);
     ++m_nextParameter;
     ++m_codeBlock->numParameters;
+
+    if (functionBody->usesThis()) {
+        emitOpcode(op_convert_this);
+        instructions().append(m_thisRegister.index());
+    }
     
     for (size_t i = 0; i < parameterCount; ++i)
         addParameter(parameters[i]);
@@ -342,7 +347,7 @@ CodeGenerator::CodeGenerator(EvalNode* evalNode, const Debugger* debugger, const
     , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
     , m_lastOpcodeID(op_end)
 {
-    emitOpcode(op_init);
+    emitOpcode(op_enter);
     codeBlock->globalData = m_globalData;
     m_codeBlock->numParameters = 1; // Allocate space for "this"
 
index a14ee1b3f9d8141779f824fbafd2c6bf5ac7015f..ed40eb5b81c4c7691da9b46f259110ba80078b21 100644 (file)
@@ -3375,7 +3375,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
 
         NEXT_OPCODE;
     }
-    BEGIN_OPCODE(op_init) {
+    BEGIN_OPCODE(op_enter) {
         size_t i = 0;
         CodeBlock* codeBlock = this->codeBlock(r);
         
@@ -3388,7 +3388,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
         ++vPC;
         NEXT_OPCODE;
     }
-    BEGIN_OPCODE(op_init_activation) {
+    BEGIN_OPCODE(op_enter_with_activation) {
         size_t i = 0;
         CodeBlock* codeBlock = this->codeBlock(r);
 
@@ -3405,6 +3405,15 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
         ++vPC;
         NEXT_OPCODE;
     }
+    BEGIN_OPCODE(op_convert_this) {
+        int thisRegister = (++vPC)->u.operand;
+        JSValue* thisVal = r[thisRegister].getJSValue();
+        if (thisVal->needsThisConversion())
+            r[thisRegister] = thisVal->toThisObject(exec);
+
+        ++vPC;
+        NEXT_OPCODE;
+    }
     BEGIN_OPCODE(op_init_arguments) {
         JSValue* activation = r[RegisterFile::OptionalCalleeActivation].getJSValue();
         Arguments* arguments;
@@ -4200,6 +4209,17 @@ NEVER_INLINE void Machine::tryCTICacheGetByID(ExecState* exec, CodeBlock* codeBl
         } \
     } while (0)
 
+
+JSValue* Machine::cti_op_convert_this(CTI_ARGS)
+{
+    JSValue* v1 = ARG_src1;
+    ExecState* exec = ARG_exec;
+
+    JSObject* result = v1->toThisObject(exec);
+    VM_CHECK_EXCEPTION_AT_END();
+    return result;
+}
+
 void Machine::cti_op_end(CTI_ARGS)
 {
     Register* r = ARG_r;
index 4f2057db1718eaba3e56151e17b627d6c96c6cef..c2a9d3638b49682d3737e8dc20793c75e5ea257f 100644 (file)
@@ -143,6 +143,7 @@ namespace JSC {
 
         static void SFX_CALL cti_timeout_check(CTI_ARGS);
 
+        static JSValue* SFX_CALL cti_op_convert_this(CTI_ARGS);
         static void SFX_CALL cti_op_end(CTI_ARGS);
         static JSValue* SFX_CALL cti_op_add(CTI_ARGS);
         static JSValue* SFX_CALL cti_op_pre_inc(CTI_ARGS);
index 425d3c361f108f750d5206fba582bc0e014556f2..f1c90291a19263c498fbabd65fad56fae2ad38b2 100644 (file)
@@ -40,9 +40,10 @@ namespace JSC {
 #define DUMP_OPCODE_STATS 0
 
     #define FOR_EACH_OPCODE_ID(macro) \
-        macro(op_init) \
-        macro(op_init_activation) \
+        macro(op_enter) \
+        macro(op_enter_with_activation) \
         macro(op_init_arguments) \
+        macro(op_convert_this) \
         \
         macro(op_unexpected_load) \
         macro(op_new_object) \
index b83a370e6688c730170f71b56e38ebdc0b57c667..2905510f6b78b1c08d978f5fa343348bd0ef35c3 100644 (file)
@@ -40,7 +40,7 @@ ASSERT_CLASS_FITS_IN_CELL(JSActivation);
 const ClassInfo JSActivation::info = { "JSActivation", 0, 0, 0 };
 
 JSActivation::JSActivation(ExecState* exec, PassRefPtr<FunctionBodyNode> functionBody, Register* registers)
-    : Base(exec->globalData().nullProtoStructureID, new JSActivationData(functionBody, registers))
+    : Base(exec->globalData().activationStructureID, new JSActivationData(functionBody, registers))
 {
 }
 
index 7361a969c6f6561e696a6a104ba4f188ac96c75b..ef45f279341730778737e65a48ba70fbe507d01a 100644 (file)
@@ -64,6 +64,8 @@ namespace JSC {
         virtual const ClassInfo* classInfo() const { return &info; }
         static const ClassInfo info;
 
+        static PassRefPtr<StructureID> createStructureID(JSValue* proto) { return StructureID::create(proto, TypeInfo(ObjectType, NeedsThisConversion)); }
+
     private:
         struct JSActivationData : public JSVariableObjectData {
             JSActivationData(PassRefPtr<FunctionBodyNode> functionBody, Register* registers)
index 6b300bd15edf6d5c76c450abbac58fed1fac0c89..bced0cd7940e7974a884fc476904527007486ea6 100644 (file)
@@ -299,6 +299,14 @@ namespace JSC {
         return asCell()->toThisObject(exec);
     }
 
+    inline bool JSValue::needsThisConversion() const
+    {
+        if (UNLIKELY(JSImmediate::isImmediate(this)))
+            return true;
+
+        return asCell()->structureID()->typeInfo().needsThisConversion();
+    }
+
     inline UString JSValue::toThisString(ExecState* exec) const
     {
         return JSImmediate::isImmediate(this) ? JSImmediate::toString(this) : asCell()->toThisString(exec);
index 463608679a04f6d3dc61e7f1bb13f270ca1ae1e6..76337317ac7926d5717be4cd017e7d29bb935e08 100644 (file)
 
 #include "ArgList.h"
 #include "CommonIdentifiers.h"
+#include "JSActivation.h"
 #include "JSClassRef.h"
 #include "JSLock.h"
+#include "JSStaticScopeObject.h"
 #include "Machine.h"
 #include "Parser.h"
 #include "collector.h"
@@ -76,6 +78,8 @@ JSGlobalData::JSGlobalData(bool isShared)
     , stringTable(&JSC::stringTable)
 #endif
     , nullProtoStructureID(JSObject::createStructureID(jsNull()))
+    , activationStructureID(JSActivation::createStructureID(jsNull()))
+    , staticScopeStructureID(JSStaticScopeObject::createStructureID(jsNull()))
     , stringStructureID(JSString::createStructureID(jsNull()))
     , numberStructureID(JSNumberCell::createStructureID(jsNull()))
     , identifierTable(createIdentifierTable())
index be6fa97956ba653411cfc1e4921835c606404e7a..937a785a38e1071f64f061800627b1d754704f15 100644 (file)
@@ -73,6 +73,8 @@ namespace JSC {
         const HashTable* stringTable;
         
         RefPtr<StructureID> nullProtoStructureID;
+        RefPtr<StructureID> activationStructureID;
+        RefPtr<StructureID> staticScopeStructureID;
         RefPtr<StructureID> stringStructureID;
         RefPtr<StructureID> numberStructureID;
 
index ab257d2cc920d8f393531cb4a6286c18017d8f6f..111665139718043b9162f1ed2fce1665ce90b3c3 100644 (file)
@@ -82,7 +82,7 @@ namespace JSC {
     #endif
         }
 
-        static PassRefPtr<StructureID> createStructureID(JSValue* proto) { return StructureID::create(proto, TypeInfo(NumberType)); }
+        static PassRefPtr<StructureID> createStructureID(JSValue* proto) { return StructureID::create(proto, TypeInfo(NumberType, NeedsThisConversion)); }
 
     private:
         JSNumberCell(JSGlobalData* globalData, double value)
index cc3bf0211f552e8420057e6d9d2e06aef51a59b1..b1528622dc0a9e293cfc602a6a5cc2b7db60f1de 100644 (file)
@@ -44,7 +44,7 @@ namespace JSC{
         
     public:
         JSStaticScopeObject(ExecState* exec, const Identifier& ident, JSValue* value, unsigned attributes)
-            : JSVariableObject(exec->globalData().nullProtoStructureID, new JSStaticScopeObjectData())
+            : JSVariableObject(exec->globalData().staticScopeStructureID, new JSStaticScopeObjectData())
         {
             d()->registerStore = value;
             symbolTable().add(ident.ustring().rep(), SymbolTableEntry(-1, attributes));
@@ -58,6 +58,8 @@ namespace JSC{
         virtual void put(ExecState*, const Identifier&, JSValue*, PutPropertySlot&);
         void putWithAttributes(ExecState*, const Identifier&, JSValue*, unsigned attributes);
 
+        static PassRefPtr<StructureID> createStructureID(JSValue* proto) { return StructureID::create(proto, TypeInfo(ObjectType, NeedsThisConversion)); }
+
     private:
         JSStaticScopeObjectData* d() { return static_cast<JSStaticScopeObjectData*>(JSVariableObject::d); }
     };
index e502c11abe32755a0603c5e548528e7d338f554b..d7c37bfc77d4f95f828d9213c5fe421337063fa3 100644 (file)
@@ -90,7 +90,7 @@ namespace JSC {
         bool canGetIndex(unsigned i) { return i < static_cast<unsigned>(m_value.size()); }
         JSString* getIndex(JSGlobalData*, unsigned);
 
-        static PassRefPtr<StructureID> createStructureID(JSValue* proto) { return StructureID::create(proto, TypeInfo(StringType)); }
+        static PassRefPtr<StructureID> createStructureID(JSValue* proto) { return StructureID::create(proto, TypeInfo(StringType, NeedsThisConversion)); }
 
     private:
         enum VPtrStealingHackType { VPtrStealingHack };
index d901c0b8d23958949a2bd75f2344fd6d16d854a4..d0e45131ebdcf57a7982fbe2d63f1673f6d0b271 100644 (file)
@@ -137,6 +137,7 @@ namespace JSC {
         bool deleteProperty(ExecState*, const Identifier& propertyName);
         bool deleteProperty(ExecState*, unsigned propertyName);
 
+        bool needsThisConversion() const;
         JSObject* toThisObject(ExecState*) const;
         UString toThisString(ExecState*) const;
         JSString* toThisJSString(ExecState*);
index ac86d9dc374341a8ae741d2c8e6952fb40e1dfd6..477e0f2168fab5a9f7e6aceee7413c86e52e5a93 100644 (file)
@@ -35,6 +35,7 @@ namespace JSC {
     static const unsigned MasqueradesAsUndefined = 1;
     static const unsigned ImplementsHasInstance = 1 << 1;
     static const unsigned OverridesHasInstance = 1 << 2;
+    static const unsigned NeedsThisConversion = 1 << 3;
 
     class TypeInfo {
         friend class CTI;
@@ -46,6 +47,7 @@ namespace JSC {
         bool masqueradesAsUndefined() const { return m_flags & MasqueradesAsUndefined; }
         bool implementsHasInstance() const { return m_flags & ImplementsHasInstance; }
         bool overridesHasInstance() const { return m_flags & OverridesHasInstance; }
+        bool needsThisConversion() const { return m_flags & NeedsThisConversion; }
 
         unsigned flags() const { return m_flags; }
     private:
index 81629938f74f2667ba1b8a4afa3174669bb65e55..fc5e5a75429323a1f19308dc10b7ceb9f142c769 100644 (file)
@@ -2192,6 +2192,7 @@ namespace JSC {
         bool containsClosures() const { return m_features & ClosureFeature; }
         bool usesArguments() const { return m_features & ArgumentsFeature; }
         void setUsesArguments() { m_features |= ArgumentsFeature; }
+        bool usesThis() const { return m_features & ThisFeature; }
 
         VarStack& varStack() { return m_varStack; }
         FunctionStack& functionStack() { return m_functionStack; }
index 1e44c110c8857724e75df4007ac49d977e1b14fe..4d6fea3660787965477eeb504a0448b59e5d04c5 100644 (file)
@@ -1,3 +1,13 @@
+2008-10-03  Maciej Stachowiak  <mjs@apple.com>
+
+        Reviewed by Cameron Zwarich.
+        
+        - test case for: "this" object in methods called on primitives should be wrapper object
+
+        * fast/js/primitive-method-this-expected.txt: Added.
+        * fast/js/primitive-method-this.html: Added.
+        * fast/js/resources/primitive-method-this.js: Added.
+
 2008-10-03  Simon Fraser  <simon.fraser@apple.com>
 
         Reviewed by Darin Adler
diff --git a/LayoutTests/fast/js/primitive-method-this-expected.txt b/LayoutTests/fast/js/primitive-method-this-expected.txt
new file mode 100644 (file)
index 0000000..90c2025
--- /dev/null
@@ -0,0 +1,13 @@
+This test checks that methods called directly on primitive types get the wrapper, not the primitive, as the 'this' object.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS (1).thisType() is 'object'
+PASS (2.3).thisType() is 'object'
+PASS 'xxx'.thisType() is 'object'
+PASS (false).thisType() is 'object'
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/primitive-method-this.html b/LayoutTests/fast/js/primitive-method-this.html
new file mode 100644 (file)
index 0000000..f64a328
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="resources/js-test-style.css">
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="resources/primitive-method-this.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/resources/primitive-method-this.js b/LayoutTests/fast/js/resources/primitive-method-this.js
new file mode 100644 (file)
index 0000000..b12f26f
--- /dev/null
@@ -0,0 +1,17 @@
+description(
+
+"This test checks that methods called directly on primitive types get the wrapper, not the primitive, as the 'this' object."
+
+);
+
+
+String.prototype.thisType = function() { return typeof this; };
+Number.prototype.thisType = function() { return typeof this; };
+Boolean.prototype.thisType = function() { return typeof this; };
+
+shouldBe("(1).thisType()", "'object'");
+shouldBe("(2.3).thisType()", "'object'");
+shouldBe("'xxx'.thisType()", "'object'");
+shouldBe("(false).thisType()", "'object'");
+
+successfullyParsed = true;
index 0e144c3e15be467e26a16c462ce59c6db6985653..7d50f1b7a80ba43bc25ba23c11ec92603c71b0dd 100644 (file)
@@ -1,3 +1,14 @@
+2008-10-03  Maciej Stachowiak  <mjs@apple.com>
+
+        Reviewed by Cameron Zwarich.
+
+        - "this" object in methods called on primitives should be wrapper object
+        https://bugs.webkit.org/show_bug.cgi?id=21362
+
+        Updated so toThis conversion for the split window is handled properly.
+
+        * bindings/scripts/CodeGeneratorJS.pm:
+
 2008-10-03  Sam Weinig  <sam@webkit.org>
 
         Reviewed by David "The Motivator" Hyatt.
index a242b54106d391eb5a6b27aad57faa87496a7412..99a55b6aaff5e0c7b2031279bd1271a694ed8fbb 100644 (file)
@@ -459,6 +459,13 @@ sub GenerateHeader
     push(@headerContent, "    virtual const JSC::ClassInfo* classInfo() const { return &s_info; }\n");
     push(@headerContent, "    static const JSC::ClassInfo s_info;\n\n");
 
+    # Structure ID
+    if ($interfaceName eq "DOMWindow") {
+        push(@headerContent, "    static PassRefPtr<JSC::StructureID> createStructureID(JSC::JSValue* proto)\n" .
+             "    {\n" .
+             "        return JSC::StructureID::create(proto, JSC::TypeInfo(JSC::ObjectType, JSC::ImplementsHasInstance | JSC::NeedsThisConversion));\n" .
+             "    }\n\n");
+    }
     # Custom mark function
     push(@headerContent, "    virtual void mark();\n\n") if $dataNode->extendedAttributes->{"CustomMarkFunction"};