Removed the assumption that "final" objects have a fixed number of inline slots
authorggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 4 Oct 2012 04:03:14 +0000 (04:03 +0000)
committerggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 4 Oct 2012 04:03:14 +0000 (04:03 +0000)
https://bugs.webkit.org/show_bug.cgi?id=98332

Reviewed by Filip Pizlo.

This is a step toward object size inference.

I replaced the inline storage capacity constant with a data member per
structure, set the the maximum supported value for the constant to 100,
then fixed what broke. (Note that even though this patch increases the
theoretical maximum inline capacity, it doesn't change any actual inline
capacity.)

* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::compileGetDirectOffset): These functions just get a rename:
the constant they need is the first out of line offset along the offset
number line, which is not necessarily the same thing (and is, in this
patch, never the same thing) as the inline capacity of any given object.

(JSC::JIT::emit_op_get_by_pname):
* jit/JITPropertyAccess32_64.cpp: This function changes functionality,
since it needs to convert from the abstract offset number line to an
actual offset in memory, and it can't assume that inline and out-of-line
offsets are contiguous on the number line.

(JSC::JIT::compileGetDirectOffset): Updated for rename.

(JSC::JIT::emit_op_get_by_pname): Same as emit_op_get_by_pname above.

* llint/LowLevelInterpreter.asm: Updated to mirror changes in PropertyOffset.h,
since we duplicate values from there.

* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm: Just like the JIT, most things are just
renames, and get_by_pname changes to do more math. I also standardized
offset calculations to use a hard-coded "-2", to match the JIT. This
isn't really better, but it makes global search and replace easier,
should we choose to refactor this code not to hard-code constants.

I also renamed loadPropertyAtVariableOffsetKnownNotFinal to
loadPropertyAtVariableOffsetKnownNotInline in order to sever the assumption
that inline capacity is tied to object type, and I changed the 64bit LLInt
to use this -- not using this previously seems to have been an oversight.

* runtime/JSObject.cpp:
(JSC::JSObject::visitChildren):
(JSC::JSFinalObject::visitChildren):
* runtime/JSObject.h:
(JSC::JSObject::offsetForLocation):
(JSNonFinalObject):
(JSC::JSFinalObject::createStructure):
(JSFinalObject):
(JSC::JSFinalObject::finishCreation): Updated for above changes.

* runtime/JSPropertyNameIterator.h:
(JSPropertyNameIterator):
(JSC::JSPropertyNameIterator::finishCreation): Store the inline capacity
of our object, since it's not a constant.

(JSC::JSPropertyNameIterator::getOffset): Removed. This function was
wrong. Luckily, it was also unused, since the C++ interpreter is gone.

* runtime/PropertyMapHashTable.h:
(PropertyTable): Use a helper function instead of hard-coding assumptions
about object types.

(JSC::PropertyTable::nextOffset):
* runtime/PropertyOffset.h:
(JSC):
(JSC::checkOffset):
(JSC::validateOffset):
(JSC::isInlineOffset):
(JSC::numberOfSlotsForLastOffset):
(JSC::propertyOffsetFor): Refactored these functions to take inline capacity
as an argument, since it's not fixed at compile time anymore.

* runtime/Structure.cpp:
(JSC::Structure::Structure):
(JSC::Structure::flattenDictionaryStructure):
(JSC::Structure::putSpecificValue):
* runtime/Structure.h:
(Structure):
(JSC::Structure::outOfLineCapacity):
(JSC::Structure::hasInlineStorage):
(JSC::Structure::inlineCapacity):
(JSC::Structure::inlineSize):
(JSC::Structure::firstValidOffset):
(JSC::Structure::lastValidOffset):
(JSC::Structure::create): Removed some hard-coded assumptions about inline
capacity and object type, and replaced with more liberal use of helper functions.

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

15 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/jit/JITPropertyAccess.cpp
Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
Source/JavaScriptCore/llint/LowLevelInterpreter.asm
Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
Source/JavaScriptCore/runtime/JSObject.cpp
Source/JavaScriptCore/runtime/JSObject.h
Source/JavaScriptCore/runtime/JSPropertyNameIterator.h
Source/JavaScriptCore/runtime/PropertyMapHashTable.h
Source/JavaScriptCore/runtime/PropertyOffset.h
Source/JavaScriptCore/runtime/Structure.cpp
Source/JavaScriptCore/runtime/Structure.h

index bcd9ae8..4baafb4 100644 (file)
@@ -1,3 +1,100 @@
+2012-10-03  Geoffrey Garen  <ggaren@apple.com>
+
+        Removed the assumption that "final" objects have a fixed number of inline slots
+        https://bugs.webkit.org/show_bug.cgi?id=98332
+
+        Reviewed by Filip Pizlo.
+
+        This is a step toward object size inference.
+
+        I replaced the inline storage capacity constant with a data member per
+        structure, set the the maximum supported value for the constant to 100,
+        then fixed what broke. (Note that even though this patch increases the
+        theoretical maximum inline capacity, it doesn't change any actual inline
+        capacity.)
+
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::compileGetDirectOffset): These functions just get a rename:
+        the constant they need is the first out of line offset along the offset
+        number line, which is not necessarily the same thing (and is, in this
+        patch, never the same thing) as the inline capacity of any given object.
+
+        (JSC::JIT::emit_op_get_by_pname):
+        * jit/JITPropertyAccess32_64.cpp: This function changes functionality,
+        since it needs to convert from the abstract offset number line to an
+        actual offset in memory, and it can't assume that inline and out-of-line
+        offsets are contiguous on the number line.
+
+        (JSC::JIT::compileGetDirectOffset): Updated for rename.
+
+        (JSC::JIT::emit_op_get_by_pname): Same as emit_op_get_by_pname above.
+
+        * llint/LowLevelInterpreter.asm: Updated to mirror changes in PropertyOffset.h,
+        since we duplicate values from there.
+
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm: Just like the JIT, most things are just
+        renames, and get_by_pname changes to do more math. I also standardized
+        offset calculations to use a hard-coded "-2", to match the JIT. This
+        isn't really better, but it makes global search and replace easier,
+        should we choose to refactor this code not to hard-code constants.
+
+        I also renamed loadPropertyAtVariableOffsetKnownNotFinal to
+        loadPropertyAtVariableOffsetKnownNotInline in order to sever the assumption
+        that inline capacity is tied to object type, and I changed the 64bit LLInt
+        to use this -- not using this previously seems to have been an oversight.
+
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::visitChildren):
+        (JSC::JSFinalObject::visitChildren):
+        * runtime/JSObject.h:
+        (JSC::JSObject::offsetForLocation):
+        (JSNonFinalObject):
+        (JSC::JSFinalObject::createStructure):
+        (JSFinalObject):
+        (JSC::JSFinalObject::finishCreation): Updated for above changes.
+
+        * runtime/JSPropertyNameIterator.h:
+        (JSPropertyNameIterator):
+        (JSC::JSPropertyNameIterator::finishCreation): Store the inline capacity
+        of our object, since it's not a constant.
+
+        (JSC::JSPropertyNameIterator::getOffset): Removed. This function was
+        wrong. Luckily, it was also unused, since the C++ interpreter is gone.
+
+        * runtime/PropertyMapHashTable.h:
+        (PropertyTable): Use a helper function instead of hard-coding assumptions
+        about object types.
+
+        (JSC::PropertyTable::nextOffset):
+        * runtime/PropertyOffset.h:
+        (JSC):
+        (JSC::checkOffset):
+        (JSC::validateOffset):
+        (JSC::isInlineOffset):
+        (JSC::numberOfSlotsForLastOffset):
+        (JSC::propertyOffsetFor): Refactored these functions to take inline capacity
+        as an argument, since it's not fixed at compile time anymore.
+
+        * runtime/Structure.cpp:
+        (JSC::Structure::Structure):
+        (JSC::Structure::flattenDictionaryStructure):
+        (JSC::Structure::putSpecificValue):
+        * runtime/Structure.h:
+        (Structure):
+        (JSC::Structure::outOfLineCapacity):
+        (JSC::Structure::hasInlineStorage):
+        (JSC::Structure::inlineCapacity):
+        (JSC::Structure::inlineSize):
+        (JSC::Structure::firstValidOffset):
+        (JSC::Structure::lastValidOffset):
+        (JSC::Structure::create): Removed some hard-coded assumptions about inline
+        capacity and object type, and replaced with more liberal use of helper functions.
+
 2012-10-03  Michael Saboff  <msaboff@apple.com>
 
         OpaqueJSString doesn't optimally handle 8 bit strings
index 70709b5..5dbfaf3 100644 (file)
@@ -4004,14 +4004,14 @@ void SpeculativeJIT::compile(Node& node)
         m_jit.loadPtr(JITCompiler::Address(globalObjectGPR, JSObject::butterflyOffset()), resultPayloadGPR);
         m_jit.load32(JITCompiler::Address(resolveInfoGPR, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), resolveInfoGPR);
 #if DFG_ENABLE(JIT_ASSERT)
-        JITCompiler::Jump isOutOfLine = m_jit.branch32(JITCompiler::GreaterThanOrEqual, resolveInfoGPR, TrustedImm32(inlineStorageCapacity));
+        JITCompiler::Jump isOutOfLine = m_jit.branch32(JITCompiler::GreaterThanOrEqual, resolveInfoGPR, TrustedImm32(firstOutOfLineOffset));
         m_jit.breakpoint();
         isOutOfLine.link(&m_jit);
 #endif
         m_jit.neg32(resolveInfoGPR);
         m_jit.signExtend32ToPtr(resolveInfoGPR, resolveInfoGPR);
-        m_jit.load32(JITCompiler::BaseIndex(resultPayloadGPR, resolveInfoGPR, JITCompiler::TimesEight, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag) + (inlineStorageCapacity - 2) * static_cast<ptrdiff_t>(sizeof(JSValue))), resultTagGPR);
-        m_jit.load32(JITCompiler::BaseIndex(resultPayloadGPR, resolveInfoGPR, JITCompiler::TimesEight, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload) + (inlineStorageCapacity - 2) * static_cast<ptrdiff_t>(sizeof(JSValue))), resultPayloadGPR);
+        m_jit.load32(JITCompiler::BaseIndex(resultPayloadGPR, resolveInfoGPR, JITCompiler::TimesEight, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag) + (firstOutOfLineOffset - 2) * static_cast<ptrdiff_t>(sizeof(JSValue))), resultTagGPR);
+        m_jit.load32(JITCompiler::BaseIndex(resultPayloadGPR, resolveInfoGPR, JITCompiler::TimesEight, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload) + (firstOutOfLineOffset - 2) * static_cast<ptrdiff_t>(sizeof(JSValue))), resultPayloadGPR);
 
         addSlowPathGenerator(
             slowPathCall(
index d7cec27..a4fe435 100644 (file)
@@ -3973,14 +3973,14 @@ void SpeculativeJIT::compile(Node& node)
         // Fast case
         m_jit.load32(JITCompiler::Address(resolveInfoGPR, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), resolveInfoGPR);
 #if DFG_ENABLE(JIT_ASSERT)
-        JITCompiler::Jump isOutOfLine = m_jit.branch32(JITCompiler::GreaterThanOrEqual, resolveInfoGPR, TrustedImm32(inlineStorageCapacity));
+        JITCompiler::Jump isOutOfLine = m_jit.branch32(JITCompiler::GreaterThanOrEqual, resolveInfoGPR, TrustedImm32(firstOutOfLineOffset));
         m_jit.breakpoint();
         isOutOfLine.link(&m_jit);
 #endif
         m_jit.neg32(resolveInfoGPR);
         m_jit.signExtend32ToPtr(resolveInfoGPR, resolveInfoGPR);
         m_jit.loadPtr(JITCompiler::Address(globalObjectGPR, JSObject::butterflyOffset()), resultGPR);
-        m_jit.loadPtr(JITCompiler::BaseIndex(resultGPR, resolveInfoGPR, JITCompiler::ScalePtr, (inlineStorageCapacity - 2) * static_cast<ptrdiff_t>(sizeof(JSValue))), resultGPR);
+        m_jit.loadPtr(JITCompiler::BaseIndex(resultGPR, resolveInfoGPR, JITCompiler::ScalePtr, (firstOutOfLineOffset - 2) * static_cast<ptrdiff_t>(sizeof(JSValue))), resultGPR);
         
         addSlowPathGenerator(
             slowPathCall(
index b4d52e2..e6a7bc1 100644 (file)
@@ -159,16 +159,16 @@ void JIT::compileGetDirectOffset(RegisterID base, RegisterID result, RegisterID
     ASSERT(sizeof(JSValue) == 8);
     
     if (finalObjectMode == MayBeFinal) {
-        Jump isInline = branch32(LessThan, offset, TrustedImm32(inlineStorageCapacity));
+        Jump isInline = branch32(LessThan, offset, TrustedImm32(firstOutOfLineOffset));
         loadPtr(Address(base, JSObject::butterflyOffset()), scratch);
         neg32(offset);
         Jump done = jump();
         isInline.link(this);
-        addPtr(TrustedImm32(JSObject::offsetOfInlineStorage() - (inlineStorageCapacity - 2) * sizeof(EncodedJSValue)), base, scratch);
+        addPtr(TrustedImm32(JSObject::offsetOfInlineStorage() - (firstOutOfLineOffset - 2) * sizeof(EncodedJSValue)), base, scratch);
         done.link(this);
     } else {
 #if !ASSERT_DISABLED
-        Jump isOutOfLine = branch32(GreaterThanOrEqual, offset, TrustedImm32(inlineStorageCapacity));
+        Jump isOutOfLine = branch32(GreaterThanOrEqual, offset, TrustedImm32(firstOutOfLineOffset));
         breakpoint();
         isOutOfLine.link(this);
 #endif
@@ -176,7 +176,7 @@ void JIT::compileGetDirectOffset(RegisterID base, RegisterID result, RegisterID
         neg32(offset);
     }
     signExtend32ToPtr(offset, offset);
-    loadPtr(BaseIndex(scratch, offset, ScalePtr, (inlineStorageCapacity - 2) * static_cast<ptrdiff_t>(sizeof(JSValue))), result);
+    loadPtr(BaseIndex(scratch, offset, ScalePtr, (firstOutOfLineOffset - 2) * sizeof(EncodedJSValue)), result);
 }
 
 void JIT::emit_op_get_by_pname(Instruction* currentInstruction)
@@ -199,7 +199,10 @@ void JIT::emit_op_get_by_pname(Instruction* currentInstruction)
     load32(addressFor(i), regT3);
     sub32(TrustedImm32(1), regT3);
     addSlowCase(branch32(AboveOrEqual, regT3, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_numCacheableSlots))));
-    add32(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_offsetBase)), regT3);
+    Jump inlineProperty = branch32(Below, regT3, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructureInlineCapacity)));
+    add32(TrustedImm32(firstOutOfLineOffset), regT3);
+    sub32(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructureInlineCapacity)), regT3);
+    inlineProperty.link(this);
     compileGetDirectOffset(regT0, regT0, regT3, regT1);
 
     emitPutVirtualRegister(dst, regT0);
index ed561a2..c8343b4 100644 (file)
@@ -1025,24 +1025,24 @@ void JIT::compileGetDirectOffset(RegisterID base, RegisterID resultTag, Register
     ASSERT(sizeof(JSValue) == 8);
     
     if (finalObjectMode == MayBeFinal) {
-        Jump isInline = branch32(LessThan, offset, TrustedImm32(inlineStorageCapacity));
+        Jump isInline = branch32(LessThan, offset, TrustedImm32(firstOutOfLineOffset));
         loadPtr(Address(base, JSObject::butterflyOffset()), base);
         neg32(offset);
         Jump done = jump();
         isInline.link(this);
-        addPtr(TrustedImmPtr(JSObject::offsetOfInlineStorage() - (inlineStorageCapacity - 2) * sizeof(EncodedJSValue)), base);
+        addPtr(TrustedImmPtr(JSObject::offsetOfInlineStorage() - (firstOutOfLineOffset - 2) * sizeof(EncodedJSValue)), base);
         done.link(this);
     } else {
 #if !ASSERT_DISABLED
-        Jump isOutOfLine = branch32(GreaterThanOrEqual, offset, TrustedImm32(inlineStorageCapacity));
+        Jump isOutOfLine = branch32(GreaterThanOrEqual, offset, TrustedImm32(firstOutOfLineOffset));
         breakpoint();
         isOutOfLine.link(this);
 #endif
         loadPtr(Address(base, JSObject::butterflyOffset()), base);
         neg32(offset);
     }
-    load32(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload) + (inlineStorageCapacity - 2) * sizeof(EncodedJSValue)), resultPayload);
-    load32(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag) + (inlineStorageCapacity - 2) * sizeof(EncodedJSValue)), resultTag);
+    load32(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload) + (firstOutOfLineOffset - 2) * sizeof(EncodedJSValue)), resultPayload);
+    load32(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag) + (firstOutOfLineOffset - 2) * sizeof(EncodedJSValue)), resultTag);
 }
 
 void JIT::emit_op_get_by_pname(Instruction* currentInstruction)
@@ -1067,7 +1067,10 @@ void JIT::emit_op_get_by_pname(Instruction* currentInstruction)
     load32(addressFor(i), regT3);
     sub32(TrustedImm32(1), regT3);
     addSlowCase(branch32(AboveOrEqual, regT3, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_numCacheableSlots))));
-    add32(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_offsetBase)), regT3);
+    Jump inlineProperty = branch32(Below, regT3, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructureInlineCapacity)));
+    add32(TrustedImm32(firstOutOfLineOffset), regT3);
+    sub32(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructureInlineCapacity)), regT3);
+    inlineProperty.link(this);
     compileGetDirectOffset(regT2, regT1, regT0, regT3);    
     
     emitStore(dst, regT1, regT0);
index e347ccc..b811c6b 100644 (file)
@@ -89,12 +89,8 @@ const LLIntReturnPC = ArgumentCount + TagOffset
 # String flags.
 const HashFlags8BitBuffer = 64
 
-# Property storage constants
-if JSVALUE64
-    const InlineStorageCapacity = 6
-else
-    const InlineStorageCapacity = 7
-end
+# Copied from PropertyOffset.h
+const firstOutOfLineOffset = 100
 
 # Allocation constants
 if JSVALUE64
index 6af544d..ed275cb 100644 (file)
@@ -937,24 +937,24 @@ _llint_op_is_string:
     dispatch(3)
 
 
-macro loadPropertyAtVariableOffsetKnownNotFinal(propertyOffset, objectAndStorage, tag, payload)
-    assert(macro (ok) bigteq propertyOffset, InlineStorageCapacity, ok end)
+macro loadPropertyAtVariableOffsetKnownNotInline(propertyOffset, objectAndStorage, tag, payload)
+    assert(macro (ok) bigteq propertyOffset, firstOutOfLineOffset, ok end)
     negi propertyOffset
     loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage
-    loadi TagOffset + (InlineStorageCapacity - 1) * 8 - sizeof IndexingHeader[objectAndStorage, propertyOffset, 8], tag
-    loadi PayloadOffset + (InlineStorageCapacity - 1) * 8 - sizeof IndexingHeader[objectAndStorage, propertyOffset, 8], payload
+    loadi TagOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffset, 8], tag
+    loadi PayloadOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffset, 8], payload
 end
 
 macro loadPropertyAtVariableOffset(propertyOffset, objectAndStorage, tag, payload)
-    bilt propertyOffset, InlineStorageCapacity, .isInline
+    bilt propertyOffset, firstOutOfLineOffset, .isInline
     loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage
     negi propertyOffset
     jmp .ready
 .isInline:
-    addp JSFinalObject::m_inlineStorage - (InlineStorageCapacity - 1) * 8 + sizeof IndexingHeader, objectAndStorage
+    addp JSFinalObject::m_inlineStorage - (firstOutOfLineOffset - 2) * 8, objectAndStorage
 .ready:
-    loadi TagOffset + (InlineStorageCapacity - 1) * 8 - sizeof IndexingHeader[objectAndStorage, propertyOffset, 8], tag
-    loadi PayloadOffset + (InlineStorageCapacity - 1) * 8 - sizeof IndexingHeader[objectAndStorage, propertyOffset, 8], payload
+    loadi TagOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffset, 8], tag
+    loadi PayloadOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffset, 8], payload
 end
 
 macro resolveGlobal(size, slow)
@@ -968,7 +968,7 @@ macro resolveGlobal(size, slow)
     loadp JSCell::m_structure[t0], t1
     bpneq t1, 12[PC], slow
     loadi 16[PC], t1
-    loadPropertyAtVariableOffsetKnownNotFinal(t1, t0, t2, t3)
+    loadPropertyAtVariableOffsetKnownNotInline(t1, t0, t2, t3)
     loadi 4[PC], t0
     storei t2, TagOffset[cfr, t0, 8]
     storei t3, PayloadOffset[cfr, t0, 8]
@@ -1364,7 +1364,10 @@ _llint_op_get_by_pname:
     loadi [cfr, t0, 8], t0
     subi 1, t0
     biaeq t0, JSPropertyNameIterator::m_numCacheableSlots[t3], .opGetByPnameSlow
-    addi JSPropertyNameIterator::m_offsetBase[t3], t0
+    bilt t0, JSPropertyNameIterator::m_cachedStructureInlineCapacity[t3], .opGetByPnameInlineProperty
+    addi firstOutOfLineOffset, t0
+    subi JSPropertyNameIterator::m_cachedStructureInlineCapacity[t3], t0
+.opGetByPnameInlineProperty:
     loadPropertyAtVariableOffset(t0, t2, t1, t3)
     loadi 4[PC], t0
     storei t1, TagOffset[cfr, t0, 8]
index 826f2e4..813a94b 100644 (file)
@@ -796,23 +796,23 @@ _llint_op_is_string:
     dispatch(3)
 
 
-macro loadPropertyAtVariableOffsetKnownNotFinal(propertyOffsetAsPointer, objectAndStorage, value)
-    assert(macro (ok) bigteq propertyOffsetAsPointer, InlineStorageCapacity, ok end)
+macro loadPropertyAtVariableOffsetKnownNotInline(propertyOffsetAsPointer, objectAndStorage, value)
+    assert(macro (ok) bigteq propertyOffsetAsPointer, firstOutOfLineOffset, ok end)
     negp propertyOffsetAsPointer
     loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage
-    loadp (InlineStorageCapacity - 1) * 8 - sizeof IndexingHeader[objectAndStorage, propertyOffsetAsPointer, 8], value
+    loadp (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffsetAsPointer, 8], value
 end
 
 macro loadPropertyAtVariableOffset(propertyOffsetAsInt, objectAndStorage, value)
-    bilt propertyOffsetAsInt, InlineStorageCapacity, .isInline
+    bilt propertyOffsetAsInt, firstOutOfLineOffset, .isInline
     loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage
     negi propertyOffsetAsInt
     sxi2p propertyOffsetAsInt, propertyOffsetAsInt
     jmp .ready
 .isInline:
-    addp JSFinalObject::m_inlineStorage - (InlineStorageCapacity - 1) * 8 + sizeof IndexingHeader, objectAndStorage
+    addp JSFinalObject::m_inlineStorage - (firstOutOfLineOffset - 2) * 8, objectAndStorage
 .ready:
-    loadp (InlineStorageCapacity - 1) * 8 - sizeof IndexingHeader[objectAndStorage, propertyOffsetAsInt, 8], value
+    loadp (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffsetAsInt, 8], value
 end
 
 macro resolveGlobal(size, slow)
@@ -826,7 +826,7 @@ macro resolveGlobal(size, slow)
     loadp JSCell::m_structure[t0], t1
     bpneq t1, 24[PB, PC, 8], slow
     loadis 32[PB, PC, 8], t1
-    loadPropertyAtVariableOffset(t1, t0, t2)
+    loadPropertyAtVariableOffsetKnownNotInline(t1, t0, t2)
     loadis 8[PB, PC, 8], t0
     storep t2, [cfr, t0, 8]
     loadp (size - 1) * 8[PB, PC, 8], t0
@@ -1208,7 +1208,10 @@ _llint_op_get_by_pname:
     loadi PayloadOffset[cfr, t3, 8], t3
     subi 1, t3
     biaeq t3, JSPropertyNameIterator::m_numCacheableSlots[t1], .opGetByPnameSlow
-    addi JSPropertyNameIterator::m_offsetBase[t1], t3
+    bilt t3, JSPropertyNameIterator::m_cachedStructureInlineCapacity[t1], .opGetByPnameInlineProperty
+    addi firstOutOfLineOffset, t3
+    subi JSPropertyNameIterator::m_cachedStructureInlineCapacity[t1], t3
+.opGetByPnameInlineProperty:
     loadPropertyAtVariableOffset(t3, t0, t0)
     loadis 8[PB, PC, 8], t1
     storep t0, [cfr, t1, 8]
index 94dee5e..e550d90 100644 (file)
@@ -182,7 +182,7 @@ void JSObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
 
     Butterfly* butterfly = thisObject->butterfly();
     if (butterfly)
-        thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSizeForKnownNonFinalObject());
+        thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize());
 
 #if !ASSERT_DISABLED
     visitor.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation;
@@ -202,9 +202,9 @@ void JSFinalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
 
     Butterfly* butterfly = thisObject->butterfly();
     if (butterfly)
-        thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSizeForKnownFinalObject());
+        thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize());
 
-    size_t storageSize = thisObject->structure()->inlineSizeForKnownFinalObject();
+    size_t storageSize = thisObject->structure()->inlineSize();
     visitor.appendValues(thisObject->inlineStorage(), storageSize);
 
 #if !ASSERT_DISABLED
index c9bf791..40804c3 100644 (file)
@@ -461,10 +461,10 @@ namespace JSC {
         {
             PropertyOffset result;
             size_t offsetInInlineStorage = location - inlineStorageUnsafe();
-            if (offsetInInlineStorage < static_cast<size_t>(inlineStorageCapacity))
+            if (offsetInInlineStorage < static_cast<size_t>(firstOutOfLineOffset))
                 result = offsetInInlineStorage;
             else
-                result = outOfLineStorage() - location + (inlineStorageCapacity - 1);
+                result = outOfLineStorage() - location + (firstOutOfLineOffset - 1);
             validateOffset(result, structure()->typeInfo().type());
             return result;
         }
@@ -685,11 +685,6 @@ namespace JSC {
             return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
         }
 
-        static bool hasInlineStorage()
-        {
-            return false;
-        }
-
     protected:
         explicit JSNonFinalObject(JSGlobalData& globalData, Structure* structure, Butterfly* butterfly = 0)
             : JSObject(globalData, structure, butterfly)
@@ -717,17 +712,13 @@ namespace JSC {
         static JSFinalObject* create(ExecState*, Structure*);
         static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
         {
-            return Structure::create(globalData, globalObject, prototype, TypeInfo(FinalObjectType, StructureFlags), &s_info);
+            return Structure::create(globalData, globalObject, prototype, TypeInfo(FinalObjectType, StructureFlags), &s_info, NonArray, INLINE_STORAGE_CAPACITY);
         }
 
         JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
 
         static JS_EXPORTDATA const ClassInfo s_info;
 
-        static bool hasInlineStorage()
-        {
-            return true;
-        }
     protected:
         void visitChildrenCommon(SlotVisitor&);
         
@@ -735,8 +726,7 @@ namespace JSC {
         {
             Base::finishCreation(globalData);
             ASSERT(!(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) % sizeof(double)));
-            ASSERT(this->structure()->inlineCapacity() == static_cast<unsigned>(inlineStorageCapacity));
-            ASSERT(this->structure()->totalStorageCapacity() == static_cast<unsigned>(inlineStorageCapacity));
+            ASSERT(structure()->totalStorageCapacity() == structure()->inlineCapacity());
             ASSERT(classInfo());
         }
 
index 4bbe567..e59a5c6 100644 (file)
@@ -59,14 +59,6 @@ namespace JSC {
 
         static void visitChildren(JSCell*, SlotVisitor&);
 
-        bool getOffset(size_t i, PropertyOffset& offset)
-        {
-            if (i >= m_numCacheableSlots)
-                return false;
-            offset = i + m_offsetBase;
-            return true;
-        }
-
         JSValue get(ExecState*, JSObject*, size_t i);
         size_t size() { return m_jsStringsSize; }
 
@@ -90,7 +82,7 @@ namespace JSC {
             PropertyNameArrayData::PropertyNameVector& propertyNameVector = propertyNameArrayData->propertyNameVector();
             for (size_t i = 0; i < m_jsStringsSize; ++i)
                 m_jsStrings[i].set(exec->globalData(), this, jsOwnedString(exec, propertyNameVector[i].string()));
-            m_offsetBase = object->structure()->firstValidOffset();
+            m_cachedStructureInlineCapacity = object->structure()->inlineCapacity();
         }
 
     private:
@@ -102,7 +94,7 @@ namespace JSC {
         WriteBarrier<StructureChain> m_cachedPrototypeChain;
         uint32_t m_numCacheableSlots;
         uint32_t m_jsStringsSize;
-        PropertyOffset m_offsetBase;
+        unsigned m_cachedStructureInlineCapacity;
         OwnArrayPtr<WriteBarrier<Unknown> > m_jsStrings;
     };
 
index 2d0f27a..9c6ddb2 100644 (file)
@@ -178,7 +178,7 @@ public:
     PropertyOffset getDeletedOffset();
     void addDeletedOffset(PropertyOffset);
     
-    PropertyOffset nextOffset(JSType);
+    PropertyOffset nextOffset(PropertyOffset inlineCapacity);
 
     // Copy this PropertyTable, ensuring the copy has at least the capacity provided.
     PassOwnPtr<PropertyTable> copy(JSGlobalData&, JSCell* owner, unsigned newCapacity);
@@ -486,15 +486,12 @@ inline void PropertyTable::addDeletedOffset(PropertyOffset offset)
     m_deletedOffsets->append(offset);
 }
 
-inline PropertyOffset PropertyTable::nextOffset(JSType type)
+inline PropertyOffset PropertyTable::nextOffset(PropertyOffset inlineCapacity)
 {
     if (hasDeletedOffset())
         return getDeletedOffset();
-    
-    if (type == FinalObjectType)
-        return size();
-    
-    return size() + firstOutOfLineOffset;
+
+    return propertyOffsetFor(size(), inlineCapacity);
 }
 
 inline PassOwnPtr<PropertyTable> PropertyTable::copy(JSGlobalData& globalData, JSCell* owner, unsigned newCapacity)
index 2aea298..1a2bba4 100644 (file)
@@ -26,7 +26,6 @@
 #ifndef PropertyOffset_h
 #define PropertyOffset_h
 
-#include "JSType.h"
 #include <wtf/Platform.h>
 #include <wtf/StdLibExtras.h>
 #include <wtf/UnusedParam.h>
@@ -42,14 +41,13 @@ namespace JSC {
 typedef int PropertyOffset;
 
 static const PropertyOffset invalidOffset = -1;
-static const PropertyOffset inlineStorageCapacity = INLINE_STORAGE_CAPACITY;
-static const PropertyOffset firstOutOfLineOffset = inlineStorageCapacity;
+static const PropertyOffset firstOutOfLineOffset = 100;
 
 // Declare all of the functions because they tend to do forward calls.
 inline void checkOffset(PropertyOffset);
-inline void checkOffset(PropertyOffset, JSType);
+inline void checkOffset(PropertyOffset, PropertyOffset inlineCapacity);
 inline void validateOffset(PropertyOffset);
-inline void validateOffset(PropertyOffset, JSType);
+inline void validateOffset(PropertyOffset, PropertyOffset inlineCapacity);
 inline bool isValidOffset(PropertyOffset);
 inline bool isInlineOffset(PropertyOffset);
 inline bool isOutOfLineOffset(PropertyOffset);
@@ -57,9 +55,7 @@ inline size_t offsetInInlineStorage(PropertyOffset);
 inline size_t offsetInOutOfLineStorage(PropertyOffset);
 inline size_t offsetInRespectiveStorage(PropertyOffset);
 inline size_t numberOfOutOfLineSlotsForLastOffset(PropertyOffset);
-inline size_t numberOfSlotsForLastOffset(PropertyOffset, JSType);
-inline PropertyOffset nextPropertyOffsetFor(PropertyOffset, JSType);
-inline PropertyOffset firstPropertyOffsetFor(JSType);
+inline size_t numberOfSlotsForLastOffset(PropertyOffset, PropertyOffset inlineCapacity);
 
 inline void checkOffset(PropertyOffset offset)
 {
@@ -67,14 +63,14 @@ inline void checkOffset(PropertyOffset offset)
     ASSERT(offset >= invalidOffset);
 }
 
-inline void checkOffset(PropertyOffset offset, JSType type)
+inline void checkOffset(PropertyOffset offset, PropertyOffset inlineCapacity)
 {
     UNUSED_PARAM(offset);
-    UNUSED_PARAM(type);
+    UNUSED_PARAM(inlineCapacity);
     ASSERT(offset >= invalidOffset);
     ASSERT(offset == invalidOffset
-           || type == FinalObjectType
-           || isOutOfLineOffset(offset));
+        || offset < inlineCapacity
+        || isOutOfLineOffset(offset));
 }
 
 inline void validateOffset(PropertyOffset offset)
@@ -83,9 +79,9 @@ inline void validateOffset(PropertyOffset offset)
     ASSERT(isValidOffset(offset));
 }
 
-inline void validateOffset(PropertyOffset offset, JSType type)
+inline void validateOffset(PropertyOffset offset, PropertyOffset inlineCapacity)
 {
-    checkOffset(offset, type);
+    checkOffset(offset, inlineCapacity);
     ASSERT(isValidOffset(offset));
 }
 
@@ -98,7 +94,7 @@ inline bool isValidOffset(PropertyOffset offset)
 inline bool isInlineOffset(PropertyOffset offset)
 {
     checkOffset(offset);
-    return offset < inlineStorageCapacity;
+    return offset < firstOutOfLineOffset;
 }
 
 inline bool isOutOfLineOffset(PropertyOffset offset)
@@ -136,28 +132,24 @@ inline size_t numberOfOutOfLineSlotsForLastOffset(PropertyOffset offset)
     return offset - firstOutOfLineOffset + 1;
 }
 
-inline size_t numberOfSlotsForLastOffset(PropertyOffset offset, JSType type)
+inline size_t numberOfSlotsForLastOffset(PropertyOffset offset, PropertyOffset inlineCapacity)
 {
-    checkOffset(offset, type);
-    if (type == FinalObjectType)
+    checkOffset(offset, inlineCapacity);
+    if (offset < inlineCapacity)
         return offset + 1;
-    return numberOfOutOfLineSlotsForLastOffset(offset);
+    return inlineCapacity + numberOfOutOfLineSlotsForLastOffset(offset);
 }
 
-inline PropertyOffset nextPropertyOffsetFor(PropertyOffset offset, JSType type)
+inline PropertyOffset propertyOffsetFor(PropertyOffset propertyNumber, PropertyOffset inlineCapacity)
 {
-    checkOffset(offset, type);
-    if (type != FinalObjectType && offset == invalidOffset)
-        return firstOutOfLineOffset;
-    return offset + 1;
-}
-
-inline PropertyOffset firstPropertyOffsetFor(JSType type)
-{
-    return nextPropertyOffsetFor(invalidOffset, type);
+    PropertyOffset offset = propertyNumber;
+    if (offset >= inlineCapacity) {
+        offset += firstOutOfLineOffset;
+        offset -= inlineCapacity;
+    }
+    return offset;
 }
 
 } // namespace JSC
 
 #endif // PropertyOffset_h
-
index 8261d2c..8f88d59 100644 (file)
@@ -149,7 +149,7 @@ void Structure::dumpStatistics()
 #endif
 }
 
-Structure::Structure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType)
+Structure::Structure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, PropertyOffset inlineCapacity)
     : JSCell(globalData, globalData.structureStructure.get())
     , m_typeInfo(typeInfo)
     , m_indexingType(indexingType)
@@ -158,6 +158,7 @@ Structure::Structure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSV
     , m_classInfo(classInfo)
     , m_transitionWatchpointSet(InitializedWatching)
     , m_outOfLineCapacity(0)
+    , m_inlineCapacity(inlineCapacity)
     , m_offset(invalidOffset)
     , m_dictionaryKind(NoneDictionaryKind)
     , m_isPinnedPropertyTable(false)
@@ -182,6 +183,7 @@ Structure::Structure(JSGlobalData& globalData)
     , m_classInfo(&s_info)
     , m_transitionWatchpointSet(InitializedWatching)
     , m_outOfLineCapacity(0)
+    , m_inlineCapacity(0)
     , m_offset(invalidOffset)
     , m_dictionaryKind(NoneDictionaryKind)
     , m_isPinnedPropertyTable(false)
@@ -204,6 +206,7 @@ Structure::Structure(JSGlobalData& globalData, const Structure* previous)
     , m_classInfo(previous->m_classInfo)
     , m_transitionWatchpointSet(InitializedWatching)
     , m_outOfLineCapacity(previous->m_outOfLineCapacity)
+    , m_inlineCapacity(previous->m_inlineCapacity)
     , m_offset(invalidOffset)
     , m_dictionaryKind(previous->m_dictionaryKind)
     , m_isPinnedPropertyTable(false)
@@ -609,20 +612,21 @@ Structure* Structure::flattenDictionaryStructure(JSGlobalData& globalData, JSObj
         ASSERT(m_propertyTable);
 
         size_t propertyCount = m_propertyTable->size();
+
+        // Holds our values compacted by insertion order.
         Vector<JSValue> values(propertyCount);
-        
+
+        // Copies out our values from their hashed locations, compacting property table offsets as we go.
         unsigned i = 0;
-        PropertyOffset firstOffset = firstPropertyOffsetFor(m_typeInfo.type());
         PropertyTable::iterator end = m_propertyTable->end();
         for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter, ++i) {
             values[i] = object->getDirectOffset(iter->offset);
-            // Update property table to have the new property offsets
-            iter->offset = i + firstOffset;
+            iter->offset = propertyOffsetFor(i, m_inlineCapacity);
         }
         
-        // Copy the original property values into their final locations
+        // Copies in our values to their compacted locations.
         for (unsigned i = 0; i < propertyCount; i++)
-            object->putDirectOffset(globalData, firstOffset + i, values[i]);
+            object->putDirectOffset(globalData, propertyOffsetFor(i, m_inlineCapacity), values[i]);
 
         m_propertyTable->clearDeletedOffsets();
     }
@@ -760,7 +764,7 @@ PropertyOffset Structure::putSpecificValue(JSGlobalData& globalData, PropertyNam
     if (!m_propertyTable)
         createPropertyMap();
 
-    PropertyOffset newOffset = m_propertyTable->nextOffset(m_typeInfo.type());
+    PropertyOffset newOffset = m_propertyTable->nextOffset(m_inlineCapacity);
 
     m_propertyTable->add(PropertyMapEntry(globalData, this, rep, newOffset, attributes, specificValue));
 
index df3cd32..db8b47e 100644 (file)
@@ -69,7 +69,7 @@ namespace JSC {
 
         typedef JSCell Base;
 
-        static Structure* create(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = 0);
+        static Structure* create(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = NonArray, PropertyOffset inlineCapacity = 0);
 
     protected:
         void finishCreation(JSGlobalData& globalData)
@@ -179,24 +179,6 @@ namespace JSC {
             ASSERT(structure()->classInfo() == &s_info);
             return m_outOfLineCapacity;
         }
-        unsigned outOfLineSizeForKnownFinalObject() const
-        {
-            ASSERT(m_typeInfo.type() == FinalObjectType);
-            if (m_propertyTable) {
-                unsigned totalSize = m_propertyTable->propertyStorageSize();
-                if (totalSize < static_cast<unsigned>(inlineStorageCapacity))
-                    return 0;
-                return totalSize - inlineStorageCapacity;
-            }
-            return numberOfOutOfLineSlotsForLastOffset(m_offset);
-        }
-        unsigned outOfLineSizeForKnownNonFinalObject() const
-        {
-            ASSERT(m_typeInfo.type() != FinalObjectType);
-            if (m_propertyTable)
-                return m_propertyTable->propertyStorageSize();
-            return numberOfOutOfLineSlotsForLastOffset(m_offset);
-        }
         unsigned outOfLineSize() const
         {
             ASSERT(structure()->classInfo() == &s_info);
@@ -211,31 +193,20 @@ namespace JSC {
         }
         bool hasInlineStorage() const
         {
-            return m_typeInfo.type() == FinalObjectType;
+            return !!m_inlineCapacity;
         }
         unsigned inlineCapacity() const
         {
-            if (hasInlineStorage())
-                return inlineStorageCapacity;
-            return 0;
+            return m_inlineCapacity;
         }
-        unsigned inlineSizeForKnownFinalObject() const
+        unsigned inlineSize() const
         {
-            ASSERT(m_typeInfo.type() == FinalObjectType);
             unsigned result;
             if (m_propertyTable)
                 result = m_propertyTable->propertyStorageSize();
             else
                 result = m_offset + 1;
-            if (result > static_cast<unsigned>(inlineStorageCapacity))
-                return inlineStorageCapacity;
-            return result;
-        }
-        unsigned inlineSize() const
-        {
-            if (!hasInlineStorage())
-                return 0;
-            return inlineSizeForKnownFinalObject();
+            return std::min<unsigned>(result, m_inlineCapacity);
         }
         unsigned totalStorageSize() const
         {
@@ -253,16 +224,12 @@ namespace JSC {
         {
             if (hasInlineStorage())
                 return 0;
-            return inlineStorageCapacity;
+            return firstOutOfLineOffset;
         }
         PropertyOffset lastValidOffset() const
         {
-            if (m_propertyTable) {
-                PropertyOffset size = m_propertyTable->propertyStorageSize();
-                if (!hasInlineStorage())
-                    size += inlineStorageCapacity;
-                return size - 1;
-            }
+            if (m_propertyTable)
+                return propertyOffsetFor(m_propertyTable->propertyStorageSize() - 1, m_inlineCapacity);
             return m_offset;
         }
         bool isValidOffset(PropertyOffset offset) const
@@ -383,7 +350,7 @@ namespace JSC {
     private:
         friend class LLIntOffsetsExtractor;
 
-        JS_EXPORT_PRIVATE Structure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = 0);
+        JS_EXPORT_PRIVATE Structure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType, PropertyOffset inlineCapacity);
         Structure(JSGlobalData&);
         Structure(JSGlobalData&, const Structure*);
 
@@ -459,6 +426,8 @@ namespace JSC {
         mutable InlineWatchpointSet m_transitionWatchpointSet;
 
         uint32_t m_outOfLineCapacity;
+        uint8_t m_inlineCapacity;
+        COMPILE_ASSERT(firstOutOfLineOffset < 256, firstOutOfLineOffset_fits);
 
         // m_offset does not account for anonymous slots
         PropertyOffset m_offset;
@@ -475,11 +444,11 @@ namespace JSC {
         unsigned m_staticFunctionReified;
     };
 
-    inline Structure* Structure::create(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType)
+    inline Structure* Structure::create(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, PropertyOffset inlineCapacity)
     {
         ASSERT(globalData.structureStructure);
         ASSERT(classInfo);
-        Structure* structure = new (NotNull, allocateCell<Structure>(globalData.heap)) Structure(globalData, globalObject, prototype, typeInfo, classInfo, indexingType);
+        Structure* structure = new (NotNull, allocateCell<Structure>(globalData.heap)) Structure(globalData, globalObject, prototype, typeInfo, classInfo, indexingType, inlineCapacity);
         structure->finishCreation(globalData);
         return structure;
     }