diff options
Diffstat (limited to 'Source/JavaScriptCore')
53 files changed, 837 insertions, 497 deletions
diff --git a/Source/JavaScriptCore/API/JSClassRef.cpp b/Source/JavaScriptCore/API/JSClassRef.cpp index 08fa5c5e0..5f67fc37e 100644 --- a/Source/JavaScriptCore/API/JSClassRef.cpp +++ b/Source/JavaScriptCore/API/JSClassRef.cpp @@ -209,13 +209,16 @@ JSObject* OpaqueJSClass::prototype(ExecState* exec) OpaqueJSClassContextData& jsClassData = contextData(exec); - if (!jsClassData.cachedPrototype) { - // Recursive, but should be good enough for our purposes - jsClassData.cachedPrototype = PassWeak<JSObject>(JSCallbackObject<JSNonFinalObject>::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackObjectStructure(), prototypeClass, &jsClassData), 0); // set jsClassData as the object's private data, so it can clear our reference on destruction - if (parentClass) { - if (JSObject* prototype = parentClass->prototype(exec)) - jsClassData.cachedPrototype->setPrototype(exec->globalData(), prototype); - } + if (JSObject* prototype = jsClassData.cachedPrototype.get()) + return prototype; + + // Recursive, but should be good enough for our purposes + JSObject* prototype = JSCallbackObject<JSNonFinalObject>::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackObjectStructure(), prototypeClass, &jsClassData); // set jsClassData as the object's private data, so it can clear our reference on destruction + if (parentClass) { + if (JSObject* parentPrototype = parentClass->prototype(exec)) + prototype->setPrototype(exec->globalData(), parentPrototype); } - return jsClassData.cachedPrototype.get(); + + jsClassData.cachedPrototype = PassWeak<JSObject>(prototype, 0); + return prototype; } diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog index 0774438d1..38f229734 100644 --- a/Source/JavaScriptCore/ChangeLog +++ b/Source/JavaScriptCore/ChangeLog @@ -1,3 +1,377 @@ +2012-05-10 Gavin Barraclough <barraclough@apple.com> + + Remove op_get_callee + + Rubber stamped by Geoff Garen. + + This is now redundant. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + * bytecode/Opcode.h: + (JSC): + (JSC::padOpcodeName): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCapabilities.h: + (JSC::DFG::canCompileOpcode): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC): + * jit/JITOpcodes32_64.cpp: + (JSC): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + +2012-05-10 Gavin Barraclough <barraclough@apple.com> + + Cache inheritorID on JSFunction + https://bugs.webkit.org/show_bug.cgi?id=85853 + + Reviewed by Geoff Garen & Filip Pizlo. + + An object's prototype is indicated via its structure. To create an otherwise + empty object with object A as its prototype, we require a structure with its + prototype set to point to A. We wish to use this same structure for all empty + objects created with a prototype of A, so we presently store this structure as + a property of A, known as the inheritorID. + + When a function F is invoked as a constructor, where F has a property 'prototype' + set to point to A, in order to create the 'this' value for the constructor to + use the following steps are taken: + - the 'prototype' proptery of F is read, via a regular [[Get]] access. + - the inheritorID internal property of the prototype is read. + - a new, empty object is constructed with its structure set to point to inheritorID. + + There are two drawbacks to the current approach: + - it requires that every object has an inheritorID field. + - it requires a [[Get]] access on every constructor call to access the 'prototype' property. + + Instead, switch to caching a copy of the inheritorID on the function. Constructor + calls now only need read the internal property from the callee, saving a [[Get]]. + This also means that JSObject::m_inheritorID is no longer commonly read, and in a + future patch we can move to storing this in a more memory efficient fashion. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + * bytecode/Opcode.h: + (JSC): + (JSC::padOpcodeName): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::execute): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGNodeType.h: + (DFG): + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + * jit/JITInlineMethods.h: + (JSC::JIT::emitAllocateJSFunction): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_create_this): + (JSC::JIT::emitSlow_op_create_this): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_create_this): + (JSC::JIT::emitSlow_op_create_this): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/JSFunction.cpp: + (JSC::JSFunction::JSFunction): + (JSC::JSFunction::cacheInheritorID): + (JSC): + (JSC::JSFunction::put): + (JSC::JSFunction::defineOwnProperty): + * runtime/JSFunction.h: + (JSC::JSFunction::cachedInheritorID): + (JSFunction): + (JSC::JSFunction::offsetOfCachedInheritorID): + +2012-05-10 Michael Saboff <msaboff@apple.com> + + Enh: Hash Const JSString in Backing Stores to Save Memory + https://bugs.webkit.org/show_bug.cgi?id=86024 + + Reviewed by Filip Pizlo. + + During garbage collection, each marking thread keeps a HashMap of + strings. While visiting via MarkStack::copyAndAppend(), we check to + see if the string we are visiting is already in the HashMap. If not + we add it. If so, we change the reference to the current string we're + visiting to the prior string. + + To somewhat reduce the performance impact of this change, if a string + is unique at the end of a marking it will not be checked during further + GC phases. In some cases this won't catch all duplicates, but we are + trying to catch the growth of duplicate strings. + + * heap/Heap.cpp: + (JSC::Heap::markRoots): + * heap/MarkStack.cpp: + (JSC::MarkStackThreadSharedData::resetChildren): New method called by the + main thread to reset the slave threads. This is primarily done to + clear the m_uniqueStrings HashMap. + (JSC): + (JSC::MarkStackThreadSharedData::markingThreadMain): + (JSC::MarkStackThreadSharedData::markingThreadStartFunc): + (JSC::MarkStackThreadSharedData::MarkStackThreadSharedData): + (JSC::MarkStackThreadSharedData::reset): + (JSC::MarkStack::reset): Added call to clear m_uniqueStrings. + (JSC::MarkStack::internalAppend): New method that performs the hash consting. + (JSC::SlotVisitor::copyAndAppend): Changed to call the new hash consting + internalAppend() + * heap/MarkStack.h: + (MarkStackThreadSharedData): + (MarkStack): + (JSC::MarkStack::sharedData): + * runtime/JSString.h: + (JSString): Added m_isHashConstSingleton flag, accessors for the flag and + code to initialize the flag. + (JSC::JSString::finishCreation): + (JSC::JSString::isHashConstSingleton): + (JSC::JSString::clearHashConstSingleton): + (JSC::JSString::setHashConstSingleton): + (JSC::JSRopeString::finishCreation): + +2012-05-09 Filip Pizlo <fpizlo@apple.com> + + JIT memory allocator is not returning memory to the OS on Darwin + https://bugs.webkit.org/show_bug.cgi?id=86047 + <rdar://problem/11414948> + + Reviewed by Geoff Garen. + + Work around the problem by using a different madvise() flag, but only for the JIT memory + allocator. Also put in ASSERTs that the call is actually working. + + * jit/ExecutableAllocatorFixedVMPool.cpp: + (JSC::FixedVMPoolExecutableAllocator::notifyNeedPage): + (JSC::FixedVMPoolExecutableAllocator::notifyPageIsFree): + +2012-05-09 Filip Pizlo <fpizlo@apple.com> + + It should be possible to get useful debug logging from the JIT memory allocator + https://bugs.webkit.org/show_bug.cgi?id=86042 + + Reviewed by Geoff Garen. + + * jit/ExecutableAllocator.h: + +2012-05-09 Gavin Barraclough <barraclough@apple.com> + + GC race condition in OpaqueJSClass::prototype + https://bugs.webkit.org/show_bug.cgi?id=86034 + + Build fix. + + * API/JSClassRef.cpp: + (OpaqueJSClass::prototype): + - Eeeep, landed bad version of patch! + +2012-05-09 Gavin Barraclough <barraclough@apple.com> + + GC race condition in OpaqueJSClass::prototype + https://bugs.webkit.org/show_bug.cgi?id=86034 + + Reviewed by Filip Pizlo. + + The bug here is basically: + if (weakref) weakref->method() + where a GC may occur between the if & the method call. + + * API/JSClassRef.cpp: + (OpaqueJSClass::prototype): + +2012-05-09 Mark Hahnenberg <mhahnenberg@apple.com> + + CopiedSpace does not add pinned blocks back to the to-space filter + https://bugs.webkit.org/show_bug.cgi?id=86011 + + Reviewed by Geoffrey Garen. + + After a collection has finished, we go through the blocks in from-space + and move any of them that are pinned into to-space. At the beginning of + collection, we reset the to-space block filter that is used during + conservative scanning and add back the blocks that are filled during the + collection. However, we neglect to add back those blocks that are moved + from from-space to to-space, which can cause the conservative scan to + think that some pinned items are not actually in CopiedSpace. + + * heap/CopiedSpace.cpp: + (JSC::CopiedSpace::doneCopying): Add the pinned blocks back to the + to-space filter. Also added a comment and assert for future readers that + indicates that it's okay that we don't also add the block to the + to-space block set since it was never removed. + + +2012-05-09 Carlos Garcia Campos <cgarcia@igalia.com> + + [GTK] Use independent version numbers for public libraries + https://bugs.webkit.org/show_bug.cgi?id=85984 + + Reviewed by Gustavo Noronha Silva. + + * GNUmakefile.am: Use LIBJAVASCRIPTCOREGTK_VERSION for library + version. + +2012-05-09 Carlos Garcia Campos <cgarcia@igalia.com> + + [GTK] Do not install JavaScriptCore platform-specific headers + https://bugs.webkit.org/show_bug.cgi?id=85983 + + Reviewed by Gustavo Noronha Silva. + + JavaScriptCore.h includes JSStringRefCF.h unconditionally. It was + renamed to JavaScript.h in r29234 and it still exists for + compatibility with mac and windows users. + + * GNUmakefile.list.am: Remove JavaScriptCore.h, JSStringRefCF.h + and JSStringRefBSTR.h from the sources and headers list. + +2012-05-08 Gavin Barraclough <barraclough@apple.com> + + ROLLING OUT r114255 + + GC in the middle of JSObject::allocatePropertyStorage can cause badness + https://bugs.webkit.org/show_bug.cgi?id=83839 + + Reviewed by nobody. + + This breaks the world, with COLLECT_ON_EVERY_ALLOCATION enabled. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * runtime/JSObject.cpp: + (JSC::JSObject::allocatePropertyStorage): + * runtime/JSObject.h: + (JSObject): + (JSC::JSObject::isUsingInlineStorage): + (JSC): + (JSC::JSObject::putDirectInternal): + (JSC::JSObject::putDirectWithoutTransition): + (JSC::JSObject::transitionTo): + * runtime/Structure.cpp: + (JSC): + * runtime/Structure.h: + (JSC::Structure::didTransition): + +2012-05-08 Mark Hahnenberg <mhahnenberg@apple.com> + + Heap should not continually allocate new pages in steady state + https://bugs.webkit.org/show_bug.cgi?id=85936 + + Reviewed by Geoff Garen. + + Currently, in steady state (i.e. a constant amount of live GC + memory with a constant rate of allocation) assuming we've just + finished a collection with X live blocks in CopiedSpace, we + increase our working set by X blocks in CopiedSpace with each + collection we perform. This is due to the fact that we allocate + until we run out of free blocks to use in the Heap before we + consider whether we should run a collection. + + In the longer term, this issue will be mostly resolved by + implementing quick release for the CopiedSpace. In the shorter + term, we should change our policy to check whether we should + allocate before trying to use a free block from the Heap. We + can change our policy to something more appropriate once we + have implemented quick release. + + This change should also have the convenient side effect of + reducing the variance in GC-heavy tests (e.g. v8-splay) due + to fact that we are doing less VM allocation during copying + collection. Overall, this patch is performance neutral across + the benchmarks we track. + + * heap/CopiedSpace.cpp: + (JSC::CopiedSpace::getFreshBlock): Shuffle the request from the BlockAllocator + around so that we only do it if the block request must succeed + i.e. after we've already checked whether we should do a collection. + * heap/MarkedAllocator.cpp: + (JSC::MarkedAllocator::allocateSlowCase): Ditto. + (JSC::MarkedAllocator::allocateBlock): We no longer have a failure mode in this + function because by the time we've called it, we've already checked whether we + should run a collection so there's no point in returning null. + * heap/MarkedAllocator.h: Removing old arguments from function declaration. + (MarkedAllocator): + +2012-05-08 Gavin Barraclough <barraclough@apple.com> + + SIGFPE on divide in classic interpreter + https://bugs.webkit.org/show_bug.cgi?id=85917 + + Rubber stamped by Oliver Hunt. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + - check for divisor of -1. + +2012-05-07 Oliver Hunt <oliver@apple.com> + + Rolling out r110287 + + RS=Filip Pizlo + + r110287 was meant to be refactoring only, but changed behavior + enough to break some websites, including qq.com. + +2012-05-07 Andy Estes <aestes@apple.com> + + ENABLE_IFRAME_SEAMLESS should be part of FEATURE_DEFINES. + + * Configurations/FeatureDefines.xcconfig: + +2012-05-07 Oliver Hunt <oliver@apple.com> + + Fix release build. + + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + +2012-05-07 Oliver Hunt <oliver@apple.com> + + LLInt doesn't check for Ropes when performing a character switch + https://bugs.webkit.org/show_bug.cgi?id=85837 + + Reviewed by Filip Pizlo. + + Make LLint check if the scrutinee of a char switch is a rope, and if + so fall back to a slow case. + + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + (LLInt): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + +2012-05-07 Eric Seidel <eric@webkit.org> + + Add ENABLE_IFRAME_SEAMLESS so Apple can turn off SEAMLESS if needed + https://bugs.webkit.org/show_bug.cgi?id=85822 + + Reviewed by Adam Barth. + + * Configurations/FeatureDefines.xcconfig: + 2012-05-05 Gavin Barraclough <barraclough@apple.com> Remove TrustedImm32::m_isPointer diff --git a/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig b/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig index 2dc145f36..91d688b53 100644 --- a/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig +++ b/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig @@ -54,6 +54,7 @@ ENABLE_GEOLOCATION = ENABLE_GEOLOCATION; ENABLE_HIGH_DPI_CANVAS = ENABLE_HIGH_DPI_CANVAS; ENABLE_ICONDATABASE = $(ENABLE_ICONDATABASE_$(REAL_PLATFORM_NAME)); ENABLE_ICONDATABASE_macosx = ENABLE_ICONDATABASE; +ENABLE_IFRAME_SEAMLESS = ENABLE_IFRAME_SEAMLESS; ENABLE_INDEXED_DATABASE = ; ENABLE_INPUT_SPEECH = ; ENABLE_INPUT_TYPE_COLOR = ; @@ -121,4 +122,4 @@ ENABLE_WEB_TIMING = ; ENABLE_WORKERS = ENABLE_WORKERS; ENABLE_XSLT = ENABLE_XSLT; -FEATURE_DEFINES = $(ENABLE_3D_RENDERING) $(ENABLE_ACCELERATED_2D_CANVAS) $(ENABLE_ANIMATION_API) $(ENABLE_BLOB) $(ENABLE_CHANNEL_MESSAGING) $(ENABLE_CSS_FILTERS) $(ENABLE_CSS_GRID_LAYOUT) $(ENABLE_CSS_SHADERS) $(ENABLE_DASHBOARD_SUPPORT) $(ENABLE_DATALIST) $(ENABLE_DATA_TRANSFER_ITEMS) $(ENABLE_DETAILS) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DIRECTORY_UPLOAD) $(ENABLE_FILE_SYSTEM) $(ENABLE_FILTERS) $(ENABLE_FULLSCREEN_API) $(ENABLE_GAMEPAD) $(ENABLE_GEOLOCATION) $(ENABLE_HIGH_DPI_CANVAS) $(ENABLE_ICONDATABASE) $(ENABLE_INDEXED_DATABASE) $(ENABLE_INPUT_TYPE_COLOR) $(ENABLE_INPUT_SPEECH) $(ENABLE_INPUT_TYPE_DATE) $(ENABLE_INPUT_TYPE_DATETIME) $(ENABLE_INPUT_TYPE_DATETIMELOCAL) $(ENABLE_INPUT_TYPE_MONTH) $(ENABLE_INPUT_TYPE_TIME) $(ENABLE_INPUT_TYPE_WEEK) $(ENABLE_JAVASCRIPT_DEBUGGER) $(ENABLE_LEGACY_NOTIFICATIONS) $(ENABLE_LINK_PREFETCH) $(ENABLE_LINK_PRERENDER) $(ENABLE_MATHML) $(ENABLE_MEDIA_SOURCE) $(ENABLE_MEDIA_STATISTICS) $(ENABLE_METER_TAG) $(ENABLE_MICRODATA) $(ENABLE_MUTATION_OBSERVERS) $(ENABLE_NOTIFICATIONS) $(ENABLE_PAGE_VISIBILITY_API) $(ENABLE_PROGRESS_TAG) $(ENABLE_QUOTA) $(ENABLE_REGISTER_PROTOCOL_HANDLER) $(ENABLE_REQUEST_ANIMATION_FRAME) $(ENABLE_SCRIPTED_SPEECH) $(ENABLE_SHADOW_DOM) $(ENABLE_SHARED_WORKERS) $(ENABLE_SQL_DATABASE) $(ENABLE_STYLE_SCOPED) $(ENABLE_SVG) $(ENABLE_SVG_DOM_OBJC_BINDINGS) $(ENABLE_SVG_FONTS) $(ENABLE_TEXT_NOTIFICATIONS_ONLY) $(ENABLE_TOUCH_ICON_LOADING) $(ENABLE_VIDEO) $(ENABLE_VIDEO_TRACK) $(ENABLE_WEBGL) $(ENABLE_WEB_AUDIO) $(ENABLE_WEB_SOCKETS) $(ENABLE_WEB_TIMING) $(ENABLE_WORKERS) $(ENABLE_XSLT); +FEATURE_DEFINES = $(ENABLE_3D_RENDERING) $(ENABLE_ACCELERATED_2D_CANVAS) $(ENABLE_ANIMATION_API) $(ENABLE_BLOB) $(ENABLE_CHANNEL_MESSAGING) $(ENABLE_CSS_FILTERS) $(ENABLE_CSS_GRID_LAYOUT) $(ENABLE_CSS_SHADERS) $(ENABLE_DASHBOARD_SUPPORT) $(ENABLE_DATALIST) $(ENABLE_DATA_TRANSFER_ITEMS) $(ENABLE_DETAILS) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DIRECTORY_UPLOAD) $(ENABLE_FILE_SYSTEM) $(ENABLE_FILTERS) $(ENABLE_FULLSCREEN_API) $(ENABLE_GAMEPAD) $(ENABLE_GEOLOCATION) $(ENABLE_HIGH_DPI_CANVAS) $(ENABLE_ICONDATABASE) $(ENABLE_IFRAME_SEAMLESS) $(ENABLE_INDEXED_DATABASE) $(ENABLE_INPUT_TYPE_COLOR) $(ENABLE_INPUT_SPEECH) $(ENABLE_INPUT_TYPE_DATE) $(ENABLE_INPUT_TYPE_DATETIME) $(ENABLE_INPUT_TYPE_DATETIMELOCAL) $(ENABLE_INPUT_TYPE_MONTH) $(ENABLE_INPUT_TYPE_TIME) $(ENABLE_INPUT_TYPE_WEEK) $(ENABLE_JAVASCRIPT_DEBUGGER) $(ENABLE_LEGACY_NOTIFICATIONS) $(ENABLE_LINK_PREFETCH) $(ENABLE_LINK_PRERENDER) $(ENABLE_MATHML) $(ENABLE_MEDIA_SOURCE) $(ENABLE_MEDIA_STATISTICS) $(ENABLE_METER_TAG) $(ENABLE_MICRODATA) $(ENABLE_MUTATION_OBSERVERS) $(ENABLE_NOTIFICATIONS) $(ENABLE_PAGE_VISIBILITY_API) $(ENABLE_PROGRESS_TAG) $(ENABLE_QUOTA) $(ENABLE_REGISTER_PROTOCOL_HANDLER) $(ENABLE_REQUEST_ANIMATION_FRAME) $(ENABLE_SCRIPTED_SPEECH) $(ENABLE_SHADOW_DOM) $(ENABLE_SHARED_WORKERS) $(ENABLE_SQL_DATABASE) $(ENABLE_STYLE_SCOPED) $(ENABLE_SVG) $(ENABLE_SVG_DOM_OBJC_BINDINGS) $(ENABLE_SVG_FONTS) $(ENABLE_TEXT_NOTIFICATIONS_ONLY) $(ENABLE_TOUCH_ICON_LOADING) $(ENABLE_VIDEO) $(ENABLE_VIDEO_TRACK) $(ENABLE_WEBGL) $(ENABLE_WEB_AUDIO) $(ENABLE_WEB_SOCKETS) $(ENABLE_WEB_TIMING) $(ENABLE_WORKERS) $(ENABLE_XSLT); diff --git a/Source/JavaScriptCore/Configurations/Version.xcconfig b/Source/JavaScriptCore/Configurations/Version.xcconfig index d7e12df22..9760c9ada 100644 --- a/Source/JavaScriptCore/Configurations/Version.xcconfig +++ b/Source/JavaScriptCore/Configurations/Version.xcconfig @@ -21,8 +21,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -MAJOR_VERSION = 536; -MINOR_VERSION = 11; +MAJOR_VERSION = 537; +MINOR_VERSION = 1; TINY_VERSION = 0; FULL_VERSION = $(MAJOR_VERSION).$(MINOR_VERSION); diff --git a/Source/JavaScriptCore/GNUmakefile.am b/Source/JavaScriptCore/GNUmakefile.am index e84528763..1ad42fd1c 100644 --- a/Source/JavaScriptCore/GNUmakefile.am +++ b/Source/JavaScriptCore/GNUmakefile.am @@ -7,7 +7,7 @@ lib_LTLIBRARIES += \ # https://bugs.webkit.org/show_bug.cgi?id=27551 is fixed we'll able to # simply rely on the usual symbol visibility flags. libjavascriptcoregtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_LDFLAGS = \ - -version-info @LIBWEBKITGTK_VERSION@ \ + -version-info @LIBJAVASCRIPTCOREGTK_VERSION@ \ $(no_undefined) nodist_EXTRA_libjavascriptcoregtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_SOURCES = \ diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am index 1b59db10c..7b3167aa1 100644 --- a/Source/JavaScriptCore/GNUmakefile.list.am +++ b/Source/JavaScriptCore/GNUmakefile.list.am @@ -3,11 +3,8 @@ javascriptcore_h_api += \ Source/JavaScriptCore/API/JSContextRef.h \ Source/JavaScriptCore/API/JSObjectRef.h \ Source/JavaScriptCore/API/JSStringRef.h \ - Source/JavaScriptCore/API/JSStringRefBSTR.h \ - Source/JavaScriptCore/API/JSStringRefCF.h \ Source/JavaScriptCore/API/JSValueRef.h \ Source/JavaScriptCore/API/JavaScript.h \ - Source/JavaScriptCore/API/JavaScriptCore.h \ Source/JavaScriptCore/API/WebKitAvailability.h javascriptcore_built_nosources += \ @@ -273,13 +270,11 @@ javascriptcore_sources += \ Source/JavaScriptCore/debugger/Debugger.h \ Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/APICast.h \ Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/APIShims.h \ - Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/JavaScriptCore.h \ Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/JavaScript.h \ Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/JSBase.h \ Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/JSContextRef.h \ Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/JSObjectRef.h \ Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/JSRetainPtr.h \ - Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/JSStringRefCF.h \ Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/JSStringRef.h \ Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/JSValueRef.h \ Source/JavaScriptCore/ForwardingHeaders/JavaScriptCore/OpaqueJSString.h \ diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def index bae50e204..951f85186 100755 --- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def +++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def @@ -62,6 +62,7 @@ EXPORTS ?addSlowCase@Identifier@JSC@@CA?AV?$PassRefPtr@VStringImpl@WTF@@@WTF@@PAVExecState@2@PAVStringImpl@4@@Z ?addSlowCase@Identifier@JSC@@CA?AV?$PassRefPtr@VStringImpl@WTF@@@WTF@@PAVJSGlobalData@2@PAVStringImpl@4@@Z ?addStaticGlobals@JSGlobalObject@JSC@@IAEXPAUGlobalPropertyInfo@12@H@Z + ?allocatePropertyStorage@JSObject@JSC@@QAEXAAVJSGlobalData@2@II@Z ?allocateSlowCase@MarkedAllocator@JSC@@AAEPAXXZ ?append@StringBuilder@WTF@@QAEXPBEI@Z ?append@StringBuilder@WTF@@QAEXPB_WI@Z @@ -209,7 +210,6 @@ EXPORTS ?globalExec@JSGlobalObject@JSC@@QAEPAVExecState@2@XZ ?globalObjectCount@Heap@JSC@@QAEIXZ ?grow@HandleSet@JSC@@AAEXXZ - ?growPropertyStorage@JSObject@JSC@@QAEPAV?$WriteBarrierBase@W4Unknown@JSC@@@2@AAVJSGlobalData@2@II@Z ?hasInstance@JSObject@JSC@@SA_NPAV12@PAVExecState@2@VJSValue@2@2@Z ?hasProperty@JSObject@JSC@@QBE_NPAVExecState@2@ABVIdentifier@2@@Z ?hasProperty@JSObject@JSC@@QBE_NPAVExecState@2@I@Z @@ -320,7 +320,6 @@ EXPORTS ?stopProfiling@Profiler@JSC@@QAE?AV?$PassRefPtr@VProfile@JSC@@@WTF@@PAVExecState@2@ABVUString@2@@Z ?stopSampling@JSGlobalData@JSC@@QAEXXZ ?substringSharingImpl@UString@JSC@@QBE?AV12@II@Z - ?suggestedNewPropertyStorageSize@Structure@JSC@@QAEIXZ ?symbolTableGet@JSVariableObject@JSC@@IAE_NABVIdentifier@2@AAVPropertyDescriptor@2@@Z ?synthesizePrototype@JSValue@JSC@@QBEPAVJSObject@2@PAVExecState@2@@Z ?thisObject@DebuggerCallFrame@JSC@@QBEPAVJSObject@2@XZ diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj index d5cf8dedc..c5a5b63be 100644 --- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj +++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj @@ -1041,6 +1041,9 @@ 86880F4C14353B2100B08D42 /* DFGSpeculativeJIT64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGSpeculativeJIT64.cpp; path = dfg/DFGSpeculativeJIT64.cpp; sourceTree = "<group>"; }; 869D04AE1193B54D00803475 /* CachedTranscendentalFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CachedTranscendentalFunction.h; sourceTree = "<group>"; }; 869EBCB60E8C6D4A008722CC /* ResultType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResultType.h; sourceTree = "<group>"; }; + 86A054461556451B00445157 /* LowLevelInterpreter.asm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm.asm; name = LowLevelInterpreter.asm; path = llint/LowLevelInterpreter.asm; sourceTree = "<group>"; }; + 86A054471556451B00445157 /* LowLevelInterpreter32_64.asm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm.asm; name = LowLevelInterpreter32_64.asm; path = llint/LowLevelInterpreter32_64.asm; sourceTree = "<group>"; }; + 86A054481556451B00445157 /* LowLevelInterpreter64.asm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm.asm; name = LowLevelInterpreter64.asm; path = llint/LowLevelInterpreter64.asm; sourceTree = "<group>"; }; 86A90ECF0EE7D51F00AB350D /* JITArithmetic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITArithmetic.cpp; sourceTree = "<group>"; }; 86ADD1430FDDEA980006EEC2 /* ARMv7Assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARMv7Assembler.h; sourceTree = "<group>"; }; 86ADD1440FDDEA980006EEC2 /* MacroAssemblerARMv7.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroAssemblerARMv7.h; sourceTree = "<group>"; }; @@ -1430,7 +1433,6 @@ 45E12D8806A49B0F00E9DF84 /* jsc.cpp */, A767FF9F14F4502900789059 /* JSCTypedArrayStubs.h */, F68EBB8C0255D4C601FF60F7 /* config.h */, - 0F46809C14BA7F4D00BFE272 /* llint */, 1432EBD70A34CAD400717B9F /* API */, 9688CB120ED12B4E001D649F /* assembler */, 969A078F0ED1D3AE00F1F681 /* bytecode */, @@ -1440,6 +1442,7 @@ 142E312A134FF0A600AFADB5 /* heap */, 1429D77A0ED20D7300B89619 /* interpreter */, 1429D92C0ED22D7000B89619 /* jit */, + 0F46809C14BA7F4D00BFE272 /* llint */, 7E39D8370EC3A388003AF11A /* parser */, 95AB831A0DA42C6900BC83F3 /* profiler */, 7EF6E0BB0EB7A1EC0079AFAF /* runtime */, @@ -1489,6 +1492,9 @@ 0F46809F14BA7F8200BFE272 /* LLIntSlowPaths.cpp */, 0F4680A014BA7F8200BFE272 /* LLIntSlowPaths.h */, 0F4680A114BA7F8200BFE272 /* LLIntOffsetsExtractor.cpp */, + 86A054461556451B00445157 /* LowLevelInterpreter.asm */, + 86A054471556451B00445157 /* LowLevelInterpreter32_64.asm */, + 86A054481556451B00445157 /* LowLevelInterpreter64.asm */, ); name = llint; sourceTree = "<group>"; diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp index 7b828acab..6a4d073bf 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp @@ -512,15 +512,9 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& dataLog("[%4d] init_lazy_reg\t %s\n", location, registerName(exec, r0).data()); break; } - case op_get_callee: { - int r0 = (++it)->u.operand; - dataLog("[%4d] op_get_callee %s\n", location, registerName(exec, r0).data()); - break; - } case op_create_this: { int r0 = (++it)->u.operand; - int r1 = (++it)->u.operand; - dataLog("[%4d] create_this %s %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data()); + dataLog("[%4d] create_this %s\n", location, registerName(exec, r0).data()); break; } case op_convert_this: { diff --git a/Source/JavaScriptCore/bytecode/Opcode.h b/Source/JavaScriptCore/bytecode/Opcode.h index a564de2da..ebf15bbd4 100644 --- a/Source/JavaScriptCore/bytecode/Opcode.h +++ b/Source/JavaScriptCore/bytecode/Opcode.h @@ -42,8 +42,7 @@ namespace JSC { macro(op_create_activation, 2) \ macro(op_init_lazy_reg, 2) \ macro(op_create_arguments, 2) \ - macro(op_create_this, 3) \ - macro(op_get_callee, 2) \ + macro(op_create_this, 2) \ macro(op_convert_this, 2) \ \ macro(op_new_object, 2) \ diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp index a520a4c78..b12bf40dc 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp @@ -442,17 +442,8 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, ScopeChainN preserveLastVar(); if (isConstructor()) { - RefPtr<RegisterID> func = newTemporary(); - RefPtr<RegisterID> funcProto = newTemporary(); - - emitOpcode(op_get_callee); - instructions().append(func->index()); - // Load prototype. - emitGetById(funcProto.get(), func.get(), globalData()->propertyNames->prototype); - emitOpcode(op_create_this); instructions().append(m_thisRegister.index()); - instructions().append(funcProto->index()); } else if (!codeBlock->isStrictMode() && (functionBody->usesThis() || codeBlock->usesEval() || m_shouldEmitDebugHooks)) { emitOpcode(op_convert_this); instructions().append(m_thisRegister.index()); diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp index 6df40ca6f..3eb5463a7 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp +++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp @@ -774,19 +774,16 @@ bool AbstractState::execute(unsigned indexInBlock) destination.merge(PredictObjectOther); break; } - + case CreateThis: { - Node& child = m_graph[node.child1()]; AbstractValue& source = forNode(node.child1()); AbstractValue& destination = forNode(nodeIndex); - if (child.shouldSpeculateFinalObject()) - source.filter(PredictFinalObject); - + source.filter(PredictFunction); destination.set(PredictFinalObject); break; } - + case NewObject: forNode(nodeIndex).set(m_codeBlock->globalObjectFor(node.codeOrigin)->emptyObjectStructure()); m_haveStructures = true; diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp index 7a2d7bdee..cc756c61e 100644 --- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp +++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp @@ -1534,8 +1534,10 @@ bool ByteCodeParser::parseBlock(unsigned limit) } case op_create_this: { - NodeIndex op1 = get(currentInstruction[2].u.operand); - set(currentInstruction[1].u.operand, addToGraph(CreateThis, op1)); + if (m_inlineStackTop->m_inlineCallFrame) + set(currentInstruction[1].u.operand, addToGraph(CreateThis, getDirect(m_inlineStackTop->m_calleeVR))); + else + set(currentInstruction[1].u.operand, addToGraph(CreateThis, addToGraph(GetCallee))); NEXT_OPCODE(op_create_this); } @@ -1565,14 +1567,6 @@ bool ByteCodeParser::parseBlock(unsigned limit) NEXT_OPCODE(op_new_regexp); } - case op_get_callee: { - if (m_inlineStackTop->m_inlineCallFrame) - set(currentInstruction[1].u.operand, getDirect(m_inlineStackTop->m_calleeVR)); - else - set(currentInstruction[1].u.operand, addToGraph(GetCallee)); - NEXT_OPCODE(op_get_callee); - } - // === Bitwise operations === case op_bitand: { diff --git a/Source/JavaScriptCore/dfg/DFGCapabilities.h b/Source/JavaScriptCore/dfg/DFGCapabilities.h index b807979ba..8aae85ef7 100644 --- a/Source/JavaScriptCore/dfg/DFGCapabilities.h +++ b/Source/JavaScriptCore/dfg/DFGCapabilities.h @@ -73,7 +73,6 @@ inline bool canCompileOpcode(OpcodeID opcodeID) case op_enter: case op_convert_this: case op_create_this: - case op_get_callee: case op_bitand: case op_bitor: case op_bitxor: diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp index 0e6e2f972..dfaf5dfe8 100644 --- a/Source/JavaScriptCore/dfg/DFGOperations.cpp +++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp @@ -209,39 +209,17 @@ EncodedJSValue DFG_OPERATION operationConvertThis(ExecState* exec, EncodedJSValu return JSValue::encode(JSValue::decode(encodedOp).toThisObject(exec)); } -inline JSCell* createThis(ExecState* exec, JSCell* prototype, JSFunction* constructor) -{ -#if !ASSERT_DISABLED - ConstructData constructData; - ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS); -#endif - - JSGlobalData& globalData = exec->globalData(); - NativeCallFrameTracer tracer(&globalData, exec); - - Structure* structure; - if (prototype->isObject()) - structure = asObject(prototype)->inheritorID(globalData); - else - structure = constructor->scope()->globalObject->emptyObjectStructure(); - - return constructEmptyObject(exec, structure); -} - -JSCell* DFG_OPERATION operationCreateThis(ExecState* exec, JSCell* prototype) +JSCell* DFG_OPERATION operationCreateThis(ExecState* exec, JSCell* constructor) { JSGlobalData* globalData = &exec->globalData(); NativeCallFrameTracer tracer(globalData, exec); - return createThis(exec, prototype, jsCast<JSFunction*>(exec->callee())); -} - -JSCell* DFG_OPERATION operationCreateThisInlined(ExecState* exec, JSCell* prototype, JSCell* constructor) -{ - JSGlobalData* globalData = &exec->globalData(); - NativeCallFrameTracer tracer(globalData, exec); +#if !ASSERT_DISABLED + ConstructData constructData; + ASSERT(jsCast<JSFunction*>(constructor)->methodTable()->getConstructData(jsCast<JSFunction*>(constructor), constructData) == ConstructTypeJS); +#endif - return createThis(exec, prototype, jsCast<JSFunction*>(constructor)); + return constructEmptyObject(exec, jsCast<JSFunction*>(constructor)->cachedInheritorID(exec)); } JSCell* DFG_OPERATION operationNewObject(ExecState* exec) diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h index 52e99cb95..601ed7665 100644 --- a/Source/JavaScriptCore/dfg/DFGOperations.h +++ b/Source/JavaScriptCore/dfg/DFGOperations.h @@ -97,8 +97,7 @@ typedef void* DFG_OPERATION (*P_DFGOperation_E)(ExecState*); // These routines are provide callbacks out to C++ implementations of operations too complex to JIT. JSCell* DFG_OPERATION operationNewObject(ExecState*); -JSCell* DFG_OPERATION operationCreateThis(ExecState*, JSCell* encodedOp1); -JSCell* DFG_OPERATION operationCreateThisInlined(ExecState*, JSCell* encodedOp1, JSCell* constructor); +JSCell* DFG_OPERATION operationCreateThis(ExecState*, JSCell* constructor); EncodedJSValue DFG_OPERATION operationConvertThis(ExecState*, EncodedJSValue encodedOp1); EncodedJSValue DFG_OPERATION operationValueAdd(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2); EncodedJSValue DFG_OPERATION operationValueAddNotNumber(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp index c156e81d0..05c418d1e 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp @@ -3029,32 +3029,17 @@ void SpeculativeJIT::compile(Node& node) // then we speculate because we want to get recompiled if it isn't (since // otherwise we'd start taking slow path a lot). - SpeculateCellOperand proto(this, node.child1()); + SpeculateCellOperand callee(this, node.child1()); GPRTemporary result(this); GPRTemporary scratch(this); - GPRReg protoGPR = proto.gpr(); + GPRReg calleeGPR = callee.gpr(); GPRReg resultGPR = result.gpr(); GPRReg scratchGPR = scratch.gpr(); - proto.use(); - + // Load the inheritorID. If the inheritorID is not set, go to slow path. + m_jit.loadPtr(MacroAssembler::Address(calleeGPR, JSFunction::offsetOfCachedInheritorID()), scratchGPR); MacroAssembler::JumpList slowPath; - - // Need to verify that the prototype is an object. If we have reason to believe - // that it's a FinalObject then we speculate on that directly. Otherwise we - // do the slow (structure-based) check. - if (at(node.child1()).shouldSpeculateFinalObject()) { - if (!isFinalObjectPrediction(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(protoGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(protoGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSFinalObject::s_info))); - } else { - m_jit.loadPtr(MacroAssembler::Address(protoGPR, JSCell::structureOffset()), scratchGPR); - slowPath.append(m_jit.branch8(MacroAssembler::Below, MacroAssembler::Address(scratchGPR, Structure::typeInfoTypeOffset()), MacroAssembler::TrustedImm32(ObjectType))); - } - - // Load the inheritorID (the Structure that objects who have protoGPR as the prototype - // use to refer to that prototype). If the inheritorID is not set, go to slow path. - m_jit.loadPtr(MacroAssembler::Address(protoGPR, JSObject::offsetOfInheritorID()), scratchGPR); slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, scratchGPR)); emitAllocateJSFinalObject(scratchGPR, resultGPR, scratchGPR, slowPath); @@ -3064,15 +3049,12 @@ void SpeculativeJIT::compile(Node& node) slowPath.link(&m_jit); silentSpillAllRegisters(resultGPR); - if (node.codeOrigin.inlineCallFrame) - callOperation(operationCreateThisInlined, resultGPR, protoGPR, node.codeOrigin.inlineCallFrame->callee.get()); - else - callOperation(operationCreateThis, resultGPR, protoGPR); + callOperation(operationCreateThis, resultGPR, calleeGPR); silentFillAllRegisters(resultGPR); done.link(&m_jit); - cellResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly); + cellResult(resultGPR, m_compileIndex); break; } diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp index a46f8f262..08e7d966d 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp @@ -3053,32 +3053,17 @@ void SpeculativeJIT::compile(Node& node) // then we speculate because we want to get recompiled if it isn't (since // otherwise we'd start taking slow path a lot). - SpeculateCellOperand proto(this, node.child1()); + SpeculateCellOperand callee(this, node.child1()); GPRTemporary result(this); GPRTemporary scratch(this); - GPRReg protoGPR = proto.gpr(); + GPRReg calleeGPR = callee.gpr(); GPRReg resultGPR = result.gpr(); GPRReg scratchGPR = scratch.gpr(); - proto.use(); - + // Load the inheritorID. If the inheritorID is not set, go to slow path. + m_jit.loadPtr(MacroAssembler::Address(calleeGPR, JSFunction::offsetOfCachedInheritorID()), scratchGPR); MacroAssembler::JumpList slowPath; - - // Need to verify that the prototype is an object. If we have reason to believe - // that it's a FinalObject then we speculate on that directly. Otherwise we - // do the slow (structure-based) check. - if (at(node.child1()).shouldSpeculateFinalObject()) { - if (!isFinalObjectPrediction(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueRegs(protoGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(protoGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSFinalObject::s_info))); - } else { - m_jit.loadPtr(MacroAssembler::Address(protoGPR, JSCell::structureOffset()), scratchGPR); - slowPath.append(m_jit.branch8(MacroAssembler::Below, MacroAssembler::Address(scratchGPR, Structure::typeInfoTypeOffset()), MacroAssembler::TrustedImm32(ObjectType))); - } - - // Load the inheritorID (the Structure that objects who have protoGPR as the prototype - // use to refer to that prototype). If the inheritorID is not set, go to slow path. - m_jit.loadPtr(MacroAssembler::Address(protoGPR, JSObject::offsetOfInheritorID()), scratchGPR); slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, scratchGPR)); emitAllocateJSFinalObject(scratchGPR, resultGPR, scratchGPR, slowPath); @@ -3088,15 +3073,12 @@ void SpeculativeJIT::compile(Node& node) slowPath.link(&m_jit); silentSpillAllRegisters(resultGPR); - if (node.codeOrigin.inlineCallFrame) - callOperation(operationCreateThisInlined, resultGPR, protoGPR, node.codeOrigin.inlineCallFrame->callee.get()); - else - callOperation(operationCreateThis, resultGPR, protoGPR); + callOperation(operationCreateThis, resultGPR, calleeGPR); silentFillAllRegisters(resultGPR); done.link(&m_jit); - cellResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly); + cellResult(resultGPR, m_compileIndex); break; } diff --git a/Source/JavaScriptCore/heap/CopiedSpace.cpp b/Source/JavaScriptCore/heap/CopiedSpace.cpp index 063ea65a2..d52c4e756 100644 --- a/Source/JavaScriptCore/heap/CopiedSpace.cpp +++ b/Source/JavaScriptCore/heap/CopiedSpace.cpp @@ -183,6 +183,9 @@ void CopiedSpace::doneCopying() CopiedBlock* block = static_cast<CopiedBlock*>(m_fromSpace->removeHead()); if (block->m_isPinned) { block->m_isPinned = false; + // We don't add the block to the toSpaceSet because it was never removed. + ASSERT(m_toSpaceSet.contains(block)); + m_toSpaceFilter.add(reinterpret_cast<Bits>(block)); m_toSpace->push(block); continue; } @@ -212,10 +215,10 @@ void CopiedSpace::doneCopying() CheckedBoolean CopiedSpace::getFreshBlock(AllocationEffort allocationEffort, CopiedBlock** outBlock) { CopiedBlock* block = 0; - if (HeapBlock* heapBlock = m_heap->blockAllocator().allocate()) - block = new (NotNull, heapBlock) CopiedBlock(heapBlock->m_allocation); - else if (allocationEffort == AllocationMustSucceed) { - if (!allocateNewBlock(&block)) { + if (allocationEffort == AllocationMustSucceed) { + if (HeapBlock* heapBlock = m_heap->blockAllocator().allocate()) + block = new (NotNull, heapBlock) CopiedBlock(heapBlock->m_allocation); + else if (!allocateNewBlock(&block)) { *outBlock = 0; ASSERT_NOT_REACHED(); return false; diff --git a/Source/JavaScriptCore/heap/Heap.cpp b/Source/JavaScriptCore/heap/Heap.cpp index d0dbc3172..d43ec1242 100644 --- a/Source/JavaScriptCore/heap/Heap.cpp +++ b/Source/JavaScriptCore/heap/Heap.cpp @@ -656,6 +656,9 @@ void Heap::markRoots(bool fullGC) visitor.doneCopying(); visitor.reset(); m_sharedData.reset(); +#if ENABLE(PARALLEL_GC) + m_sharedData.resetChildren(); +#endif m_storageSpace.doneCopying(); m_operationInProgress = NoOperation; diff --git a/Source/JavaScriptCore/heap/MarkStack.cpp b/Source/JavaScriptCore/heap/MarkStack.cpp index cf6e3513c..785444e55 100644 --- a/Source/JavaScriptCore/heap/MarkStack.cpp +++ b/Source/JavaScriptCore/heap/MarkStack.cpp @@ -36,6 +36,7 @@ #include "JSObject.h" #include "ScopeChain.h" #include "Structure.h" +#include "UString.h" #include "WriteBarrier.h" #include <wtf/MainThread.h> @@ -218,17 +219,24 @@ void MarkStackArray::stealSomeCellsFrom(MarkStackArray& other) } #if ENABLE(PARALLEL_GC) -void MarkStackThreadSharedData::markingThreadMain() +void MarkStackThreadSharedData::resetChildren() +{ + for (unsigned i = 0; i < m_slaveMarkStacks.size(); ++i) + m_slaveMarkStacks[i]->reset(); +} + +void MarkStackThreadSharedData::markingThreadMain(SlotVisitor* slotVisitor) { WTF::registerGCThread(); - SlotVisitor slotVisitor(*this); - ParallelModeEnabler enabler(slotVisitor); - slotVisitor.drainFromShared(SlotVisitor::SlaveDrain); + ParallelModeEnabler enabler(*slotVisitor); + slotVisitor->drainFromShared(SlotVisitor::SlaveDrain); + delete slotVisitor; } -void MarkStackThreadSharedData::markingThreadStartFunc(void* shared) +void MarkStackThreadSharedData::markingThreadStartFunc(void* myVisitor) { - static_cast<MarkStackThreadSharedData*>(shared)->markingThreadMain(); + SlotVisitor* slotVisitor = static_cast<SlotVisitor*>(myVisitor); + slotVisitor->sharedData().markingThreadMain(slotVisitor); } #endif @@ -241,7 +249,9 @@ MarkStackThreadSharedData::MarkStackThreadSharedData(JSGlobalData* globalData) { #if ENABLE(PARALLEL_GC) for (unsigned i = 1; i < Options::numberOfGCMarkers; ++i) { - m_markingThreads.append(createThread(markingThreadStartFunc, this, "JavaScriptCore::Marking")); + SlotVisitor* slotVisitor = new SlotVisitor(*this); + m_slaveMarkStacks.append(slotVisitor); + m_markingThreads.append(createThread(markingThreadStartFunc, slotVisitor, "JavaScriptCore::Marking")); ASSERT(m_markingThreads.last()); } #endif @@ -273,7 +283,6 @@ void MarkStackThreadSharedData::reset() #else ASSERT(m_opaqueRoots.isEmpty()); #endif - m_weakReferenceHarvesters.removeAll(); } @@ -286,6 +295,7 @@ void MarkStack::reset() #else m_opaqueRoots.clear(); #endif + m_uniqueStrings.clear(); } void MarkStack::append(ConservativeRoots& conservativeRoots) @@ -486,6 +496,34 @@ void* SlotVisitor::allocateNewSpace(void* ptr, size_t bytes) return CopiedSpace::allocateFromBlock(m_copyBlock, bytes); } +inline void MarkStack::internalAppend(JSValue* slot) +{ + ASSERT(slot); + JSValue value = *slot; + ASSERT(value); + if (!value.isCell()) + return; + + if (value.isString()) { + JSString* string = jsCast<JSString*>(value.asCell()); + if (!string->isHashConstSingleton() && string->length() > 1 && !string->isRope()) { + UniqueStringMap::AddResult addResult = m_uniqueStrings.add(string->string().impl(), value); + if (addResult.isNewEntry) + string->setHashConstSingleton(); + else { + JSValue existingJSValue = addResult.iterator->second; + if (value != existingJSValue) + jsCast<JSString*>(existingJSValue.asCell())->clearHashConstSingleton(); + *slot = existingJSValue; + return; + } + } + } + + internalAppend(value.asCell()); +} + + void SlotVisitor::copyAndAppend(void** ptr, size_t bytes, JSValue* values, unsigned length) { void* oldPtr = *ptr; @@ -499,7 +537,7 @@ void SlotVisitor::copyAndAppend(void** ptr, size_t bytes, JSValue* values, unsig newValues[i] = value; if (!value) continue; - internalAppend(value); + internalAppend(&newValues[i]); } memcpy(newPtr, oldPtr, jsValuesOffset); diff --git a/Source/JavaScriptCore/heap/MarkStack.h b/Source/JavaScriptCore/heap/MarkStack.h index 0695b1b32..48b65c069 100644 --- a/Source/JavaScriptCore/heap/MarkStack.h +++ b/Source/JavaScriptCore/heap/MarkStack.h @@ -34,12 +34,14 @@ #include "UnconditionalFinalizer.h" #include "VTableSpectrum.h" #include "WeakReferenceHarvester.h" +#include <wtf/Forward.h> #include <wtf/HashMap.h> #include <wtf/HashSet.h> #include <wtf/Vector.h> #include <wtf/Noncopyable.h> #include <wtf/OSAllocator.h> #include <wtf/PageBlock.h> +#include <wtf/text/StringHash.h> namespace JSC { @@ -171,13 +173,17 @@ namespace JSC { ~MarkStackThreadSharedData(); void reset(); - + +#if ENABLE(PARALLEL_GC) + void resetChildren(); +#endif + private: friend class MarkStack; friend class SlotVisitor; #if ENABLE(PARALLEL_GC) - void markingThreadMain(); + void markingThreadMain(SlotVisitor*); static void markingThreadStartFunc(void* heap); #endif @@ -187,6 +193,7 @@ namespace JSC { MarkStackSegmentAllocator m_segmentAllocator; Vector<ThreadIdentifier> m_markingThreads; + Vector<MarkStack*> m_slaveMarkStacks; Mutex m_markingLock; ThreadCondition m_markingCondition; @@ -221,13 +228,14 @@ namespace JSC { void addOpaqueRoot(void*); bool containsOpaqueRoot(void*); int opaqueRootCount(); - + + MarkStackThreadSharedData& sharedData() { return m_shared; } bool isEmpty() { return m_stack.isEmpty(); } void reset(); size_t visitCount() const { return m_visitCount; } - + #if ENABLE(SIMPLE_HEAP_PROFILING) VTableSpectrum m_visitedTypeCounts; #endif @@ -251,6 +259,7 @@ namespace JSC { void internalAppend(JSCell*); void internalAppend(JSValue); + void internalAppend(JSValue*); JS_EXPORT_PRIVATE void mergeOpaqueRoots(); @@ -270,6 +279,8 @@ namespace JSC { MarkStackArray m_stack; HashSet<void*> m_opaqueRoots; // Handle-owning data structures not visible to the garbage collector. + typedef HashMap<StringImpl*, JSValue> UniqueStringMap; + UniqueStringMap m_uniqueStrings; #if !ASSERT_DISABLED public: diff --git a/Source/JavaScriptCore/heap/MarkedAllocator.cpp b/Source/JavaScriptCore/heap/MarkedAllocator.cpp index b5e5fff77..01f00c376 100644 --- a/Source/JavaScriptCore/heap/MarkedAllocator.cpp +++ b/Source/JavaScriptCore/heap/MarkedAllocator.cpp @@ -68,44 +68,30 @@ void* MarkedAllocator::allocateSlowCase() if (LIKELY(result != 0)) return result; - AllocationEffort allocationEffort; - - if (m_heap->shouldCollect()) - allocationEffort = AllocationCanFail; - else - allocationEffort = AllocationMustSucceed; - - MarkedBlock* block = allocateBlock(allocationEffort); - if (block) { - addBlock(block); - void* result = tryAllocate(); - ASSERT(result); - return result; + if (m_heap->shouldCollect()) { + m_heap->collect(Heap::DoNotSweep); + + result = tryAllocate(); + if (result) + return result; } - - m_heap->collect(Heap::DoNotSweep); - - result = tryAllocate(); - - if (result) - return result; - + ASSERT(!m_heap->shouldCollect()); - addBlock(allocateBlock(AllocationMustSucceed)); - + MarkedBlock* block = allocateBlock(); + ASSERT(block); + addBlock(block); + result = tryAllocate(); ASSERT(result); return result; } -MarkedBlock* MarkedAllocator::allocateBlock(AllocationEffort allocationEffort) +MarkedBlock* MarkedAllocator::allocateBlock() { MarkedBlock* block = static_cast<MarkedBlock*>(m_heap->blockAllocator().allocate()); if (block) block = MarkedBlock::recycle(block, m_heap, m_cellSize, m_cellsNeedDestruction); - else if (allocationEffort == AllocationCanFail) - return 0; else block = MarkedBlock::create(m_heap, m_cellSize, m_cellsNeedDestruction); diff --git a/Source/JavaScriptCore/heap/MarkedAllocator.h b/Source/JavaScriptCore/heap/MarkedAllocator.h index 8ad7e925f..8b3620f08 100644 --- a/Source/JavaScriptCore/heap/MarkedAllocator.h +++ b/Source/JavaScriptCore/heap/MarkedAllocator.h @@ -41,7 +41,7 @@ private: JS_EXPORT_PRIVATE void* allocateSlowCase(); void* tryAllocate(); void* tryAllocateHelper(); - MarkedBlock* allocateBlock(AllocationEffort); + MarkedBlock* allocateBlock(); MarkedBlock::FreeList m_freeList; MarkedBlock* m_currentBlock; diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp index 1cd5719ff..89547f40a 100644 --- a/Source/JavaScriptCore/interpreter/Interpreter.cpp +++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp @@ -2448,7 +2448,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi JSValue dividend = callFrame->r(vPC[2].u.operand).jsValue(); JSValue divisor = callFrame->r(vPC[3].u.operand).jsValue(); - if (dividend.isInt32() && divisor.isInt32() && divisor.asInt32() != 0) { + if (dividend.isInt32() && divisor.isInt32() && divisor.asInt32() != 0 && divisor.asInt32() != -1) { JSValue result = jsNumber(dividend.asInt32() % divisor.asInt32()); ASSERT(result); callFrame->uncheckedR(dst) = result; @@ -4788,17 +4788,6 @@ skip_id_custom_self: vPC += OPCODE_LENGTH(op_create_activation); NEXT_INSTRUCTION(); } - DEFINE_OPCODE(op_get_callee) { - /* op_get_callee callee(r) - - Move callee into a register. - */ - - callFrame->uncheckedR(vPC[1].u.operand) = JSValue(callFrame->callee()); - - vPC += OPCODE_LENGTH(op_get_callee); - NEXT_INSTRUCTION(); - } DEFINE_OPCODE(op_create_this) { /* op_create_this this(r) proto(r) @@ -4809,7 +4798,6 @@ skip_id_custom_self: */ int thisRegister = vPC[1].u.operand; - int protoRegister = vPC[2].u.operand; JSFunction* constructor = jsCast<JSFunction*>(callFrame->callee()); #if !ASSERT_DISABLED @@ -4817,12 +4805,7 @@ skip_id_custom_self: ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS); #endif - Structure* structure; - JSValue proto = callFrame->r(protoRegister).jsValue(); - if (proto.isObject()) - structure = asObject(proto)->inheritorID(callFrame->globalData()); - else - structure = constructor->scope()->globalObject->emptyObjectStructure(); + Structure* structure = constructor->cachedInheritorID(callFrame); callFrame->uncheckedR(thisRegister) = constructEmptyObject(callFrame, structure); vPC += OPCODE_LENGTH(op_create_this); diff --git a/Source/JavaScriptCore/jit/ExecutableAllocator.h b/Source/JavaScriptCore/jit/ExecutableAllocator.h index 1ddf011cb..c1edc9752 100644 --- a/Source/JavaScriptCore/jit/ExecutableAllocator.h +++ b/Source/JavaScriptCore/jit/ExecutableAllocator.h @@ -30,6 +30,7 @@ #include <limits> #include <wtf/Assertions.h> #include <wtf/MetaAllocatorHandle.h> +#include <wtf/MetaAllocator.h> #include <wtf/PageAllocation.h> #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> diff --git a/Source/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp b/Source/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp index b4422c3df..884248b20 100644 --- a/Source/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp +++ b/Source/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp @@ -78,12 +78,26 @@ protected: virtual void notifyNeedPage(void* page) { +#if OS(DARWIN) + UNUSED_PARAM(page); +#else m_reservation.commit(page, pageSize()); +#endif } virtual void notifyPageIsFree(void* page) { +#if OS(DARWIN) + for (;;) { + int result = madvise(page, pageSize(), MADV_FREE); + if (!result) + return; + ASSERT(result == -1); + ASSERT(errno == EAGAIN); + } +#else m_reservation.decommit(page, pageSize()); +#endif } private: diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp index 01b1260c9..abc79d34b 100644 --- a/Source/JavaScriptCore/jit/JIT.cpp +++ b/Source/JavaScriptCore/jit/JIT.cpp @@ -242,7 +242,6 @@ void JIT::privateCompileMainPass() DEFINE_OP(op_call_varargs) DEFINE_OP(op_catch) DEFINE_OP(op_construct) - DEFINE_OP(op_get_callee) DEFINE_OP(op_create_this) DEFINE_OP(op_convert_this) DEFINE_OP(op_init_lazy_reg) diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h index af5076fb5..6dc0137d9 100644 --- a/Source/JavaScriptCore/jit/JIT.h +++ b/Source/JavaScriptCore/jit/JIT.h @@ -582,7 +582,6 @@ namespace JSC { void emit_op_call_put_result(Instruction*); void emit_op_catch(Instruction*); void emit_op_construct(Instruction*); - void emit_op_get_callee(Instruction*); void emit_op_create_this(Instruction*); void emit_op_convert_this(Instruction*); void emit_op_create_arguments(Instruction*); diff --git a/Source/JavaScriptCore/jit/JITInlineMethods.h b/Source/JavaScriptCore/jit/JITInlineMethods.h index cd33821f2..40985ac90 100644 --- a/Source/JavaScriptCore/jit/JITInlineMethods.h +++ b/Source/JavaScriptCore/jit/JITInlineMethods.h @@ -448,6 +448,9 @@ inline void JIT::emitAllocateJSFunction(FunctionExecutable* executable, Register // store the function's executable member storePtr(TrustedImmPtr(executable), Address(result, JSFunction::offsetOfExecutable())); + // clear the function's inheritorID + storePtr(TrustedImmPtr(0), Address(result, JSFunction::offsetOfCachedInheritorID())); + // store the function's name ASSERT(executable->nameValue()); int functionNameOffset = sizeof(JSValue) * m_codeBlock->globalObject()->functionNameOffset(); diff --git a/Source/JavaScriptCore/jit/JITOpcodes.cpp b/Source/JavaScriptCore/jit/JITOpcodes.cpp index d68f4109d..f43e98c45 100644 --- a/Source/JavaScriptCore/jit/JITOpcodes.cpp +++ b/Source/JavaScriptCore/jit/JITOpcodes.cpp @@ -1263,42 +1263,24 @@ void JIT::emit_op_convert_this(Instruction* currentInstruction) addSlowCase(branchPtr(Equal, Address(regT0, JSCell::classInfoOffset()), TrustedImmPtr(&JSString::s_info))); } -void JIT::emit_op_get_callee(Instruction* currentInstruction) -{ - unsigned result = currentInstruction[1].u.operand; - emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0); - emitPutVirtualRegister(result); -} - void JIT::emit_op_create_this(Instruction* currentInstruction) { - emitGetVirtualRegister(currentInstruction[2].u.operand, regT2); - emitJumpSlowCaseIfNotJSCell(regT2, currentInstruction[2].u.operand); - loadPtr(Address(regT2, JSCell::structureOffset()), regT1); - addSlowCase(emitJumpIfNotObject(regT1)); - - // now we know that the prototype is an object, but we don't know if it's got an - // inheritor ID - - loadPtr(Address(regT2, JSObject::offsetOfInheritorID()), regT2); + emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0); + loadPtr(Address(regT0, JSFunction::offsetOfCachedInheritorID()), regT2); addSlowCase(branchTestPtr(Zero, regT2)); // now regT2 contains the inheritorID, which is the structure that the newly // allocated object will have. emitAllocateJSFinalObject(regT2, regT0, regT1); - emitPutVirtualRegister(currentInstruction[1].u.operand); } void JIT::emitSlow_op_create_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { - linkSlowCaseIfNotJSCell(iter, currentInstruction[2].u.operand); // not a cell - linkSlowCase(iter); // not an object linkSlowCase(iter); // doesn't have an inheritor ID linkSlowCase(iter); // allocation failed JITStubCall stubCall(this, cti_op_create_this); - stubCall.addArgument(currentInstruction[2].u.operand, regT1); stubCall.call(currentInstruction[1].u.operand); } diff --git a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp index 76e11e48c..c9f8922fa 100644 --- a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp +++ b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp @@ -1523,44 +1523,24 @@ void JIT::emit_op_init_lazy_reg(Instruction* currentInstruction) emitStore(dst, JSValue()); } -void JIT::emit_op_get_callee(Instruction* currentInstruction) -{ - int dst = currentInstruction[1].u.operand; - emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0); - emitStoreCell(dst, regT0); -} - void JIT::emit_op_create_this(Instruction* currentInstruction) { - emitLoad(currentInstruction[2].u.operand, regT1, regT0); - emitJumpSlowCaseIfNotJSCell(currentInstruction[2].u.operand, regT1); - loadPtr(Address(regT0, JSCell::structureOffset()), regT1); - addSlowCase(emitJumpIfNotObject(regT1)); - - // now we know that the prototype is an object, but we don't know if it's got an - // inheritor ID - - loadPtr(Address(regT0, JSObject::offsetOfInheritorID()), regT2); + emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0); + loadPtr(Address(regT0, JSFunction::offsetOfCachedInheritorID()), regT2); addSlowCase(branchTestPtr(Zero, regT2)); // now regT2 contains the inheritorID, which is the structure that the newly // allocated object will have. emitAllocateJSFinalObject(regT2, regT0, regT1); - emitStoreCell(currentInstruction[1].u.operand, regT0); } void JIT::emitSlow_op_create_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { - linkSlowCaseIfNotJSCell(iter, currentInstruction[2].u.operand); // not a cell - linkSlowCase(iter); // not an object linkSlowCase(iter); // doesn't have an inheritor ID linkSlowCase(iter); // allocation failed - unsigned protoRegister = currentInstruction[2].u.operand; - emitLoad(protoRegister, regT1, regT0); JITStubCall stubCall(this, cti_op_create_this); - stubCall.addArgument(regT1, regT0); stubCall.call(currentInstruction[1].u.operand); } diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp index d81e68aae..73f4892ac 100644 --- a/Source/JavaScriptCore/jit/JITStubs.cpp +++ b/Source/JavaScriptCore/jit/JITStubs.cpp @@ -1286,12 +1286,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_create_this) ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS); #endif - Structure* structure; - JSValue proto = stackFrame.args[0].jsValue(); - if (proto.isObject()) - structure = asObject(proto)->inheritorID(*stackFrame.globalData); - else - structure = constructor->scope()->globalObject->emptyObjectStructure(); + Structure* structure = constructor->cachedInheritorID(callFrame); JSValue result = constructEmptyObject(callFrame, structure); return JSValue::encode(result); @@ -1497,9 +1492,7 @@ DEFINE_STUB_FUNCTION(JSObject*, op_put_by_id_transition_realloc) ASSERT(baseValue.isObject()); JSObject* base = asObject(baseValue); - JSGlobalData& globalData = *stackFrame.globalData; - PropertyStorage newStorage = base->growPropertyStorage(globalData, oldSize, newSize); - base->setPropertyStorage(globalData, newStorage, newStructure); + base->allocatePropertyStorage(*stackFrame.globalData, oldSize, newSize); return base; } diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp index 2b5161f7b..d184b6e62 100644 --- a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp +++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp @@ -458,13 +458,7 @@ LLINT_SLOW_PATH_DECL(slow_path_create_this) ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS); #endif - Structure* structure; - JSValue proto = LLINT_OP(2).jsValue(); - if (proto.isObject()) - structure = asObject(proto)->inheritorID(globalData); - else - structure = constructor->scope()->globalObject->emptyObjectStructure(); - + Structure* structure = constructor->cachedInheritorID(exec); LLINT_RETURN(constructEmptyObject(exec, structure)); } @@ -1167,6 +1161,20 @@ LLINT_SLOW_PATH_DECL(slow_path_switch_imm) LLINT_END(); } +LLINT_SLOW_PATH_DECL(slow_path_switch_char) +{ + LLINT_BEGIN(); + JSValue scrutinee = LLINT_OP_C(3).jsValue(); + ASSERT(scrutinee.isString()); + JSString* string = asString(scrutinee); + ASSERT(string->length() == 1); + int defaultOffset = pc[2].u.operand; + StringImpl* impl = string->value(exec).impl(); + CodeBlock* codeBlock = exec->codeBlock(); + pc += codeBlock->characterSwitchJumpTable(pc[1].u.operand).offsetForValue((*impl)[0], defaultOffset); + LLINT_END(); +} + LLINT_SLOW_PATH_DECL(slow_path_switch_string) { LLINT_BEGIN(); diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm index 42ab4c1e4..e1361315f 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm @@ -343,31 +343,17 @@ _llint_op_create_arguments: _llint_op_create_this: traceExecution() - loadi 8[PC], t0 - assertNotConstant(t0) - bineq TagOffset[cfr, t0, 8], CellTag, .opCreateThisSlow - loadi PayloadOffset[cfr, t0, 8], t0 - loadp JSCell::m_structure[t0], t1 - bbb Structure::m_typeInfo + TypeInfo::m_type[t1], ObjectType, .opCreateThisSlow - loadp JSObject::m_inheritorID[t0], t2 + loadp Callee[cfr], t0 + loadp JSFunction::m_cachedInheritorID[t0], t2 btpz t2, .opCreateThisSlow allocateBasicJSObject(JSFinalObjectSizeClassIndex, JSGlobalData::jsFinalObjectClassInfo, t2, t0, t1, t3, .opCreateThisSlow) loadi 4[PC], t1 storei CellTag, TagOffset[cfr, t1, 8] storei t0, PayloadOffset[cfr, t1, 8] - dispatch(3) + dispatch(2) .opCreateThisSlow: callSlowPath(_llint_slow_path_create_this) - dispatch(3) - - -_llint_op_get_callee: - traceExecution() - loadi 4[PC], t0 - loadp PayloadOffset + Callee[cfr], t1 - storei CellTag, TagOffset[cfr, t0, 8] - storei t1, PayloadOffset[cfr, t0, 8] dispatch(2) @@ -1446,8 +1432,9 @@ _llint_op_switch_char: bineq t1, CellTag, .opSwitchCharFallThrough loadp JSCell::m_structure[t0], t1 bbneq Structure::m_typeInfo + TypeInfo::m_type[t1], StringType, .opSwitchCharFallThrough + bineq JSString::m_length[t0], 1, .opSwitchCharFallThrough loadp JSString::m_value[t0], t0 - bineq StringImpl::m_length[t0], 1, .opSwitchCharFallThrough + btpz t0, .opSwitchOnRope loadp StringImpl::m_data8[t0], t1 btinz StringImpl::m_hashAndFlags[t0], HashFlags8BitBuffer, .opSwitchChar8Bit loadh [t1], t0 @@ -1465,6 +1452,10 @@ _llint_op_switch_char: .opSwitchCharFallThrough: dispatchBranch(8[PC]) +.opSwitchOnRope: + callSlowPath(_llint_slow_path_switch_char) + dispatch(0) + _llint_op_new_func: traceExecution() diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm index b28051f33..baf246b0b 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm @@ -221,29 +221,16 @@ _llint_op_create_arguments: _llint_op_create_this: traceExecution() - loadis 16[PB, PC, 8], t0 - assertNotConstant(t0) - loadp [cfr, t0, 8], t0 - btpnz t0, tagMask, .opCreateThisSlow - loadp JSCell::m_structure[t0], t1 - bbb Structure::m_typeInfo + TypeInfo::m_type[t1], ObjectType, .opCreateThisSlow - loadp JSObject::m_inheritorID[t0], t2 + loadp Callee[cfr], t0 + loadp JSFunction::m_cachedInheritorID[t0], t2 btpz t2, .opCreateThisSlow allocateBasicJSObject(JSFinalObjectSizeClassIndex, JSGlobalData::jsFinalObjectClassInfo, t2, t0, t1, t3, .opCreateThisSlow) loadis 8[PB, PC, 8], t1 storep t0, [cfr, t1, 8] - dispatch(3) + dispatch(2) .opCreateThisSlow: callSlowPath(_llint_slow_path_create_this) - dispatch(3) - - -_llint_op_get_callee: - traceExecution() - loadis 8[PB, PC, 8], t0 - loadp Callee[cfr], t1 - storep t1, [cfr, t0, 8] dispatch(2) @@ -1292,8 +1279,9 @@ _llint_op_switch_char: btpnz t1, tagMask, .opSwitchCharFallThrough loadp JSCell::m_structure[t1], t0 bbneq Structure::m_typeInfo + TypeInfo::m_type[t0], StringType, .opSwitchCharFallThrough + bineq JSString::m_length[t1], 1, .opSwitchCharFallThrough loadp JSString::m_value[t1], t0 - bineq StringImpl::m_length[t0], 1, .opSwitchCharFallThrough + btpz t0, .opSwitchOnRope loadp StringImpl::m_data8[t0], t1 btinz StringImpl::m_hashAndFlags[t0], HashFlags8BitBuffer, .opSwitchChar8Bit loadh [t1], t0 @@ -1311,6 +1299,10 @@ _llint_op_switch_char: .opSwitchCharFallThrough: dispatchInt(16[PB, PC, 8]) +.opSwitchOnRope: + callSlowPath(_llint_slow_path_switch_char) + dispatch(0) + _llint_op_new_func: traceExecution() diff --git a/Source/JavaScriptCore/parser/ASTBuilder.h b/Source/JavaScriptCore/parser/ASTBuilder.h index a173cc10f..0eb60cf89 100644 --- a/Source/JavaScriptCore/parser/ASTBuilder.h +++ b/Source/JavaScriptCore/parser/ASTBuilder.h @@ -77,6 +77,7 @@ public: : m_globalData(globalData) , m_sourceCode(sourceCode) , m_scope(globalData) + , m_evalCount(0) { } @@ -118,6 +119,7 @@ public: ParserArenaData<DeclarationStacks::VarStack>* varDeclarations() { return m_scope.m_varDeclarations; } ParserArenaData<DeclarationStacks::FunctionStack>* funcDeclarations() { return m_scope.m_funcDeclarations; } + int features() const { return m_scope.m_features; } int numConstants() const { return m_scope.m_numConstants; } void appendToComma(CommaNode* commaNode, ExpressionNode* expr) { commaNode->append(expr); } @@ -150,8 +152,17 @@ public: incConstants(); return new (m_globalData) VoidNode(lineNumber, expr); } - ExpressionNode* thisExpr(int lineNumber) { return new (m_globalData) ThisNode(lineNumber); } - ExpressionNode* createResolve(int lineNumber, const Identifier* ident, int start) { return new (m_globalData) ResolveNode(lineNumber, *ident, start); } + ExpressionNode* thisExpr(int lineNumber) + { + usesThis(); + return new (m_globalData) ThisNode(lineNumber); + } + ExpressionNode* createResolve(int lineNumber, const Identifier* ident, int start) + { + if (m_globalData->propertyNames->arguments == *ident) + usesArguments(); + return new (m_globalData) ResolveNode(lineNumber, *ident, start); + } ExpressionNode* createObjectLiteral(int lineNumber) { return new (m_globalData) ObjectLiteralNode(lineNumber); } ExpressionNode* createObjectLiteral(int lineNumber, PropertyListNode* properties) { return new (m_globalData) ObjectLiteralNode(lineNumber, properties); } @@ -252,9 +263,9 @@ public: return result; } - FunctionBodyNode* createFunctionBody(int lineNumber, ScopeFlags scopeFlags) + FunctionBodyNode* createFunctionBody(int lineNumber, bool inStrictContext) { - return FunctionBodyNode::create(m_globalData, lineNumber, scopeFlags); + return FunctionBodyNode::create(m_globalData, lineNumber, inStrictContext); } template <bool> PropertyNode* createGetterOrSetterProperty(int lineNumber, PropertyNode::Type type, const Identifier* name, ParameterNode* params, FunctionBodyNode* body, int openBracePos, int closeBracePos, int bodyStartLine, int bodyEndLine) @@ -301,6 +312,8 @@ public: StatementNode* createFuncDeclStatement(int lineNumber, const Identifier* name, FunctionBodyNode* body, ParameterNode* parameters, int openBracePos, int closeBracePos, int bodyStartLine, int bodyEndLine) { FuncDeclNode* decl = new (m_globalData) FuncDeclNode(lineNumber, *name, body, m_sourceCode->subExpression(openBracePos, closeBracePos, bodyStartLine), parameters); + if (*name == m_globalData->propertyNames->arguments) + usesArguments(); m_scope.m_funcDeclarations->data.append(decl->body()); body->setLoc(bodyStartLine, bodyEndLine); return decl; @@ -413,6 +426,8 @@ public: StatementNode* createTryStatement(int lineNumber, StatementNode* tryBlock, const Identifier* ident, StatementNode* catchBlock, StatementNode* finallyBlock, int startLine, int endLine) { TryNode* result = new (m_globalData) TryNode(lineNumber, tryBlock, *ident, catchBlock, finallyBlock); + if (catchBlock) + usesCatch(); result->setLoc(startLine, endLine); return result; } @@ -448,6 +463,7 @@ public: StatementNode* createWithStatement(int lineNumber, ExpressionNode* expr, StatementNode* statement, int start, int end, int startLine, int endLine) { + usesWith(); WithNode* result = new (m_globalData) WithNode(lineNumber, expr, statement, end, end - start); result->setLoc(startLine, endLine); return result; @@ -490,6 +506,8 @@ public: void addVar(const Identifier* ident, int attrs) { + if (m_globalData->propertyNames->arguments == *ident) + usesArguments(); m_scope.m_varDeclarations->data.append(std::make_pair(ident, attrs)); } @@ -504,6 +522,8 @@ public: return new (m_globalData) CommaNode(lineNumber, list, init); } + int evalCount() const { return m_evalCount; } + void appendBinaryExpressionInfo(int& operandStackDepth, ExpressionNode* current, int exprStart, int lhs, int rhs, bool hasAssignments) { operandStackDepth++; @@ -590,11 +610,13 @@ private: Scope(JSGlobalData* globalData) : m_varDeclarations(new (globalData) ParserArenaData<DeclarationStacks::VarStack>) , m_funcDeclarations(new (globalData) ParserArenaData<DeclarationStacks::FunctionStack>) + , m_features(0) , m_numConstants(0) { } ParserArenaData<DeclarationStacks::VarStack>* m_varDeclarations; ParserArenaData<DeclarationStacks::FunctionStack>* m_funcDeclarations; + int m_features; int m_numConstants; }; @@ -604,6 +626,15 @@ private: } void incConstants() { m_scope.m_numConstants++; } + void usesThis() { m_scope.m_features |= ThisFeature; } + void usesCatch() { m_scope.m_features |= CatchFeature; } + void usesArguments() { m_scope.m_features |= ArgumentsFeature; } + void usesWith() { m_scope.m_features |= WithFeature; } + void usesEval() + { + m_evalCount++; + m_scope.m_features |= EvalFeature; + } ExpressionNode* createNumber(int lineNumber, double d) { return new (m_globalData) NumberNode(lineNumber, d); @@ -616,6 +647,7 @@ private: Vector<AssignmentInfo, 10> m_assignmentInfoStack; Vector<pair<int, int>, 10> m_binaryOperatorStack; Vector<pair<int, int>, 10> m_unaryTokenStack; + int m_evalCount; }; ExpressionNode* ASTBuilder::makeTypeOfNode(int lineNumber, ExpressionNode* expr) @@ -765,8 +797,10 @@ ExpressionNode* ASTBuilder::makeFunctionCallNode(int lineNumber, ExpressionNode* if (func->isResolveNode()) { ResolveNode* resolve = static_cast<ResolveNode*>(func); const Identifier& identifier = resolve->identifier(); - if (identifier == m_globalData->propertyNames->eval) + if (identifier == m_globalData->propertyNames->eval) { + usesEval(); return new (m_globalData) EvalFunctionCallNode(lineNumber, args, divot, divot - start, end - divot); + } return new (m_globalData) FunctionCallResolveNode(lineNumber, identifier, args, divot, divot - start, end - divot); } if (func->isBracketAccessorNode()) { diff --git a/Source/JavaScriptCore/parser/NodeInfo.h b/Source/JavaScriptCore/parser/NodeInfo.h index e0d4ffec4..4853aec42 100644 --- a/Source/JavaScriptCore/parser/NodeInfo.h +++ b/Source/JavaScriptCore/parser/NodeInfo.h @@ -26,7 +26,7 @@ namespace JSC { template <typename T> struct NodeInfo { T m_node; - ScopeFlags m_scopeFlags; + CodeFeatures m_features; int m_numConstants; }; @@ -44,7 +44,7 @@ namespace JSC { T m_node; ParserArenaData<DeclarationStacks::VarStack>* m_varDeclarations; ParserArenaData<DeclarationStacks::FunctionStack>* m_funcDeclarations; - ScopeFlags m_scopeFlags; + CodeFeatures m_features; int m_numConstants; }; diff --git a/Source/JavaScriptCore/parser/Nodes.cpp b/Source/JavaScriptCore/parser/Nodes.cpp index 75c848bce..c32e4c73a 100644 --- a/Source/JavaScriptCore/parser/Nodes.cpp +++ b/Source/JavaScriptCore/parser/Nodes.cpp @@ -75,19 +75,19 @@ StatementNode* SourceElements::singleStatement() const // ------------------------------ ScopeNode ----------------------------- -ScopeNode::ScopeNode(JSGlobalData* globalData, int lineNumber, ScopeFlags scopeFlags) +ScopeNode::ScopeNode(JSGlobalData* globalData, int lineNumber, bool inStrictContext) : StatementNode(lineNumber) , ParserArenaRefCounted(globalData) - , m_scopeFlags(scopeFlags) + , m_features(inStrictContext ? StrictModeFeature : NoFeatures) , m_numConstants(0) , m_statements(0) { } -ScopeNode::ScopeNode(JSGlobalData* globalData, int lineNumber, const SourceCode& source, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, ScopeFlags scopeFlags, int numConstants) +ScopeNode::ScopeNode(JSGlobalData* globalData, int lineNumber, const SourceCode& source, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, CodeFeatures features, int numConstants) : StatementNode(lineNumber) , ParserArenaRefCounted(globalData) - , m_scopeFlags(scopeFlags) + , m_features(features) , m_source(source) , m_numConstants(numConstants) , m_statements(children) @@ -107,14 +107,14 @@ StatementNode* ScopeNode::singleStatement() const // ------------------------------ ProgramNode ----------------------------- -inline ProgramNode::ProgramNode(JSGlobalData* globalData, int lineNumber, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, ScopeFlags scopeFlags, int numConstants) - : ScopeNode(globalData, lineNumber, source, children, varStack, funcStack, capturedVariables, scopeFlags, numConstants) +inline ProgramNode::ProgramNode(JSGlobalData* globalData, int lineNumber, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, CodeFeatures features, int numConstants) + : ScopeNode(globalData, lineNumber, source, children, varStack, funcStack, capturedVariables, features, numConstants) { } -PassRefPtr<ProgramNode> ProgramNode::create(JSGlobalData* globalData, int lineNumber, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, ScopeFlags scopeFlags, int numConstants) +PassRefPtr<ProgramNode> ProgramNode::create(JSGlobalData* globalData, int lineNumber, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, CodeFeatures features, int numConstants) { - RefPtr<ProgramNode> node = new ProgramNode(globalData, lineNumber, children, varStack, funcStack, capturedVariables, source, scopeFlags, numConstants); + RefPtr<ProgramNode> node = new ProgramNode(globalData, lineNumber, children, varStack, funcStack, capturedVariables, source, features, numConstants); ASSERT(node->m_arena.last() == node); node->m_arena.removeLast(); @@ -125,14 +125,14 @@ PassRefPtr<ProgramNode> ProgramNode::create(JSGlobalData* globalData, int lineNu // ------------------------------ EvalNode ----------------------------- -inline EvalNode::EvalNode(JSGlobalData* globalData, int lineNumber, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, ScopeFlags scopeFlags, int numConstants) - : ScopeNode(globalData, lineNumber, source, children, varStack, funcStack, capturedVariables, scopeFlags, numConstants) +inline EvalNode::EvalNode(JSGlobalData* globalData, int lineNumber, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, CodeFeatures features, int numConstants) + : ScopeNode(globalData, lineNumber, source, children, varStack, funcStack, capturedVariables, features, numConstants) { } -PassRefPtr<EvalNode> EvalNode::create(JSGlobalData* globalData, int lineNumber, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, ScopeFlags scopeFlags, int numConstants) +PassRefPtr<EvalNode> EvalNode::create(JSGlobalData* globalData, int lineNumber, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, CodeFeatures features, int numConstants) { - RefPtr<EvalNode> node = new EvalNode(globalData, lineNumber, children, varStack, funcStack, capturedVariables, source, scopeFlags, numConstants); + RefPtr<EvalNode> node = new EvalNode(globalData, lineNumber, children, varStack, funcStack, capturedVariables, source, features, numConstants); ASSERT(node->m_arena.last() == node); node->m_arena.removeLast(); @@ -149,13 +149,13 @@ FunctionParameters::FunctionParameters(ParameterNode* firstParameter) append(parameter->ident()); } -inline FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData, int lineNumber, ScopeFlags scopeFlags) - : ScopeNode(globalData, lineNumber, scopeFlags) +inline FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData, int lineNumber, bool inStrictContext) + : ScopeNode(globalData, lineNumber, inStrictContext) { } -inline FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData, int lineNumber, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& sourceCode, ScopeFlags scopeFlags, int numConstants) - : ScopeNode(globalData, lineNumber, sourceCode, children, varStack, funcStack, capturedVariables, scopeFlags, numConstants) +inline FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData, int lineNumber, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& sourceCode, CodeFeatures features, int numConstants) + : ScopeNode(globalData, lineNumber, sourceCode, children, varStack, funcStack, capturedVariables, features, numConstants) { } @@ -172,14 +172,14 @@ void FunctionBodyNode::finishParsing(PassRefPtr<FunctionParameters> parameters, m_ident = ident; } -FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData, int lineNumber, ScopeFlags scopeFlags) +FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData, int lineNumber, bool inStrictContext) { - return new FunctionBodyNode(globalData, lineNumber, scopeFlags); + return new FunctionBodyNode(globalData, lineNumber, inStrictContext); } -PassRefPtr<FunctionBodyNode> FunctionBodyNode::create(JSGlobalData* globalData, int lineNumber, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& sourceCode, ScopeFlags scopeFlags, int numConstants) +PassRefPtr<FunctionBodyNode> FunctionBodyNode::create(JSGlobalData* globalData, int lineNumber, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& sourceCode, CodeFeatures features, int numConstants) { - RefPtr<FunctionBodyNode> node = new FunctionBodyNode(globalData, lineNumber, children, varStack, funcStack, capturedVariables, sourceCode, scopeFlags, numConstants); + RefPtr<FunctionBodyNode> node = new FunctionBodyNode(globalData, lineNumber, children, varStack, funcStack, capturedVariables, sourceCode, features, numConstants); ASSERT(node->m_arena.last() == node); node->m_arena.removeLast(); diff --git a/Source/JavaScriptCore/parser/Nodes.h b/Source/JavaScriptCore/parser/Nodes.h index f752b91e9..26c829da6 100644 --- a/Source/JavaScriptCore/parser/Nodes.h +++ b/Source/JavaScriptCore/parser/Nodes.h @@ -47,31 +47,19 @@ namespace JSC { class ScopeChainNode; class ScopeNode; - typedef unsigned short ScopeFlags; - - const ScopeFlags NoScopeFlags = 0; - - // Some scope flags propagate down the parse tree from parent scopes, like - // strict mode. They are modal to an entire set of nested scopes. - const ScopeFlags StrictModeFlag = 1 << 0; - const ScopeFlags FunctionModeFlag = 1 << 1; - const ScopeFlags AllScopeModeFlags = StrictModeFlag | FunctionModeFlag; - - // Some scope flags refer only to a specific scope, and don't propagate down - // or up. - const ScopeFlags BlockScopeFlag = 1 << 4; - const ScopeFlags AllScopeKindFlags = BlockScopeFlag; - - // Other flags reflect uses within nested scopes, and so propagate up - // from the leaves. - const ScopeFlags UsesEvalFlag = 1 << 8; - const ScopeFlags UsesArgumentsFlag = 1 << 9; - const ScopeFlags UsesWithFlag = 1 << 10; - const ScopeFlags UsesCatchFlag = 1 << 11; - const ScopeFlags UsesThisFlag = 1 << 12; - const ScopeFlags ShadowsArgumentsFlag = 1 << 13; - const ScopeFlags AllScopeUsesFlags = UsesEvalFlag | UsesArgumentsFlag | UsesWithFlag | UsesCatchFlag | UsesThisFlag | ShadowsArgumentsFlag; + typedef unsigned CodeFeatures; + + const CodeFeatures NoFeatures = 0; + const CodeFeatures EvalFeature = 1 << 0; + const CodeFeatures ArgumentsFeature = 1 << 1; + const CodeFeatures WithFeature = 1 << 2; + const CodeFeatures CatchFeature = 1 << 3; + const CodeFeatures ThisFeature = 1 << 4; + const CodeFeatures StrictModeFeature = 1 << 5; + const CodeFeatures ShadowsArgumentsFeature = 1 << 6; + const CodeFeatures AllFeatures = EvalFeature | ArgumentsFeature | WithFeature | CatchFeature | ThisFeature | StrictModeFeature | ShadowsArgumentsFeature; + enum Operator { OpEqual, OpPlusEq, @@ -1395,8 +1383,8 @@ namespace JSC { typedef DeclarationStacks::VarStack VarStack; typedef DeclarationStacks::FunctionStack FunctionStack; - ScopeNode(JSGlobalData*, int, ScopeFlags); - ScopeNode(JSGlobalData*, int, const SourceCode&, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, ScopeFlags, int numConstants); + ScopeNode(JSGlobalData*, int, bool inStrictContext); + ScopeNode(JSGlobalData*, int, const SourceCode&, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, CodeFeatures, int numConstants); using ParserArenaRefCounted::operator new; @@ -1409,26 +1397,24 @@ namespace JSC { m_capturedVariables.clear(); } - bool hasCapturedVariables() const { return !!m_capturedVariables.size(); } - size_t capturedVariableCount() const { return m_capturedVariables.size(); } - bool captures(const Identifier& ident) { return m_capturedVariables.contains(ident.impl()); } - - void addScopeFlags(ScopeFlags scopeFlags) { m_scopeFlags |= scopeFlags; } - ScopeFlags scopeFlags() const { return m_scopeFlags; } - - bool isStrictMode() const { return m_scopeFlags & StrictModeFlag; } - bool usesEval() const { return m_scopeFlags & UsesEvalFlag; } - bool usesArguments() const { return (m_scopeFlags & UsesArgumentsFlag) && !(m_scopeFlags & ShadowsArgumentsFlag); } - void setUsesArguments() { m_scopeFlags |= UsesArgumentsFlag; } - bool usesThis() const { return m_scopeFlags & UsesThisFlag; } - - bool needsActivationForMoreThanVariables() const { return m_scopeFlags & (UsesEvalFlag | UsesWithFlag | UsesCatchFlag); } - bool needsActivation() const { return hasCapturedVariables() || needsActivationForMoreThanVariables(); } - const SourceCode& source() const { return m_source; } const UString& sourceURL() const { return m_source.provider()->url(); } intptr_t sourceID() const { return m_source.provider()->asID(); } + void setFeatures(CodeFeatures features) { m_features = features; } + CodeFeatures features() { return m_features; } + + bool usesEval() const { return m_features & EvalFeature; } + bool usesArguments() const { return (m_features & ArgumentsFeature) && !(m_features & ShadowsArgumentsFeature); } + bool isStrictMode() const { return m_features & StrictModeFeature; } + void setUsesArguments() { m_features |= ArgumentsFeature; } + bool usesThis() const { return m_features & ThisFeature; } + bool needsActivationForMoreThanVariables() const { return m_features & (EvalFeature | WithFeature | CatchFeature); } + bool needsActivation() const { return (hasCapturedVariables()) || (m_features & (EvalFeature | WithFeature | CatchFeature)); } + bool hasCapturedVariables() const { return !!m_capturedVariables.size(); } + size_t capturedVariableCount() const { return m_capturedVariables.size(); } + bool captures(const Identifier& ident) { return m_capturedVariables.contains(ident.impl()); } + VarStack& varStack() { return m_varStack; } FunctionStack& functionStack() { return m_functionStack; } @@ -1448,7 +1434,7 @@ namespace JSC { ParserArena m_arena; private: - ScopeFlags m_scopeFlags; + CodeFeatures m_features; SourceCode m_source; VarStack m_varStack; FunctionStack m_functionStack; @@ -1460,12 +1446,12 @@ namespace JSC { class ProgramNode : public ScopeNode { public: static const bool isFunctionNode = false; - static PassRefPtr<ProgramNode> create(JSGlobalData*, int, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, ScopeFlags, int numConstants); + static PassRefPtr<ProgramNode> create(JSGlobalData*, int, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants); static const bool scopeIsFunction = false; private: - ProgramNode(JSGlobalData*, int, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, ScopeFlags, int numConstants); + ProgramNode(JSGlobalData*, int, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants); virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); }; @@ -1473,12 +1459,12 @@ namespace JSC { class EvalNode : public ScopeNode { public: static const bool isFunctionNode = false; - static PassRefPtr<EvalNode> create(JSGlobalData*, int, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, ScopeFlags, int numConstants); + static PassRefPtr<EvalNode> create(JSGlobalData*, int, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants); static const bool scopeIsFunction = false; private: - EvalNode(JSGlobalData*, int, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, ScopeFlags, int numConstants); + EvalNode(JSGlobalData*, int, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants); virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); }; @@ -1495,8 +1481,8 @@ namespace JSC { class FunctionBodyNode : public ScopeNode { public: static const bool isFunctionNode = true; - static FunctionBodyNode* create(JSGlobalData*, int, ScopeFlags); - static PassRefPtr<FunctionBodyNode> create(JSGlobalData*, int, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, ScopeFlags, int numConstants); + static FunctionBodyNode* create(JSGlobalData*, int, bool isStrictMode); + static PassRefPtr<FunctionBodyNode> create(JSGlobalData*, int, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants); FunctionParameters* parameters() const { return m_parameters.get(); } size_t parameterCount() const { return m_parameters->size(); } @@ -1513,8 +1499,8 @@ namespace JSC { static const bool scopeIsFunction = true; private: - FunctionBodyNode(JSGlobalData*, int, ScopeFlags); - FunctionBodyNode(JSGlobalData*, int, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, ScopeFlags, int numConstants); + FunctionBodyNode(JSGlobalData*, int, bool inStrictContext); + FunctionBodyNode(JSGlobalData*, int, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants); Identifier m_ident; Identifier m_inferredName; diff --git a/Source/JavaScriptCore/parser/Parser.cpp b/Source/JavaScriptCore/parser/Parser.cpp index a03af24df..d88a9a8b7 100644 --- a/Source/JavaScriptCore/parser/Parser.cpp +++ b/Source/JavaScriptCore/parser/Parser.cpp @@ -62,12 +62,11 @@ Parser<LexerType>::Parser(JSGlobalData* globalData, const SourceCode& source, Fu m_lexer->setCode(source, m_arena); m_functionCache = source.provider()->cache(); - ScopeFlags scopeFlags = NoScopeFlags; - if (strictness == JSParseStrict) - scopeFlags |= StrictModeFlag; + ScopeRef scope = pushScope(); if (parserMode == JSParseFunctionCode) - scopeFlags |= FunctionModeFlag; - ScopeRef scope = pushScope(scopeFlags); + scope->setIsFunction(); + if (strictness == JSParseStrict) + scope->setStrictMode(); if (parameters) { for (unsigned i = 0; i < parameters->size(); i++) scope->declareParameter(¶meters->at(i)); @@ -97,12 +96,16 @@ UString Parser<LexerType>::parseInner() IdentifierSet capturedVariables; scope->getCapturedVariables(capturedVariables); - ScopeFlags scopeFlags = scope->modeFlags() | scope->usesFlags(); + CodeFeatures features = context.features(); + if (scope->strictMode()) + features |= StrictModeFeature; + if (scope->shadowsArguments()) + features |= ShadowsArgumentsFeature; unsigned functionCacheSize = m_functionCache ? m_functionCache->byteSize() : 0; if (functionCacheSize != oldFunctionCacheSize) m_lexer->sourceProvider()->notifyCacheSizeChanged(functionCacheSize - oldFunctionCacheSize); - didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), scopeFlags, + didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), features, m_lastLine, context.numConstants(), capturedVariables); return parseError; @@ -110,13 +113,13 @@ UString Parser<LexerType>::parseInner() template <typename LexerType> void Parser<LexerType>::didFinishParsing(SourceElements* sourceElements, ParserArenaData<DeclarationStacks::VarStack>* varStack, - ParserArenaData<DeclarationStacks::FunctionStack>* funcStack, ScopeFlags scopeFlags, int lastLine, int numConstants, IdentifierSet& capturedVars) + ParserArenaData<DeclarationStacks::FunctionStack>* funcStack, CodeFeatures features, int lastLine, int numConstants, IdentifierSet& capturedVars) { m_sourceElements = sourceElements; m_varDeclarations = varStack; m_funcDeclarations = funcStack; m_capturedVariables.swap(capturedVars); - m_scopeFlags = scopeFlags; + m_features = features; m_lastLine = lastLine; m_numConstants = numConstants; } @@ -144,7 +147,7 @@ template <SourceElementsMode mode, class TreeBuilder> TreeSourceElements Parser< if (directive) { // "use strict" must be the exact literal without escape sequences or line continuation. if (!hasSetStrict && directiveLiteralLength == lengthOfUseStrictLiteral && m_globalData->propertyNames->useStrictIdentifier == *directive) { - currentScope()->setFlags(StrictModeFlag); + setStrictMode(); hasSetStrict = true; failIfFalse(isValidStrictMode()); m_lexer->setOffset(startOffset); @@ -252,8 +255,6 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVarDeclarati next(); bool hasInitializer = match(EQUAL); failIfFalseIfStrictWithNameAndMessage(declareVariable(name), "Cannot declare a variable named", name->impl(), "in strict mode."); - if (m_globalData->propertyNames->arguments == *name) - currentScope()->setFlags(UsesArgumentsFlag); context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0); if (hasInitializer) { int varDivot = tokenStart() + 1; @@ -288,8 +289,6 @@ template <class TreeBuilder> TreeConstDeclList Parser<LexerType>::parseConstDecl next(); bool hasInitializer = match(EQUAL); declareVariable(name); - if (m_globalData->propertyNames->arguments == *name) - currentScope()->setFlags(UsesArgumentsFlag); context.addVar(name, DeclarationStacks::IsConstant | (hasInitializer ? DeclarationStacks::HasInitializer : 0)); TreeExpression initializer = 0; if (hasInitializer) { @@ -512,7 +511,7 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseWithStatement { ASSERT(match(WITH)); failIfTrueWithMessage(strictMode(), "'with' statements are not valid in strict mode"); - currentScope()->setFlags(UsesWithFlag); + currentScope()->setNeedsFullActivation(); int startLine = tokenLine(); next(); consumeOrFail(OPENPAREN); @@ -527,7 +526,6 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseWithStatement TreeStatement statement = parseStatement(context, unused); failIfFalse(statement); - currentScope()->setFlags(UsesWithFlag); return context.createWithStatement(m_lexer->lastLineNumber(), expr, statement, start, end, startLine, endLine); } @@ -616,15 +614,15 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseTryStatement( int lastLine = m_lastLine; if (match(CATCH)) { - currentScope()->setFlags(UsesCatchFlag); + currentScope()->setNeedsFullActivation(); next(); consumeOrFail(OPENPAREN); matchOrFail(IDENT); ident = m_token.m_data.ident; next(); - AutoPopScopeRef catchScope(this, pushScope(currentScope()->modeFlags())); + AutoPopScopeRef catchScope(this, pushScope()); failIfFalseIfStrictWithNameAndMessage(declareVariable(ident), "Cannot declare a variable named", ident->impl(), "in strict mode"); - currentScope()->setFlags(BlockScopeFlag | UsesCatchFlag); + catchScope->preventNewDecls(); consumeOrFail(CLOSEPAREN); matchOrFail(OPENBRACE); catchBlock = parseBlockStatement(context); @@ -761,7 +759,7 @@ template <typename LexerType> template <class TreeBuilder> TreeFunctionBody Parser<LexerType>::parseFunctionBody(TreeBuilder& context) { if (match(CLOSEBRACE)) - return context.createFunctionBody(m_lexer->lastLineNumber(), currentScope()->modeFlags()); + return context.createFunctionBody(m_lexer->lastLineNumber(), strictMode()); DepthManager statementDepth(&m_statementDepth); m_statementDepth = 0; typename TreeBuilder::FunctionBodyBuilder bodyBuilder(const_cast<JSGlobalData*>(m_globalData), m_lexer.get()); @@ -772,7 +770,8 @@ template <class TreeBuilder> TreeFunctionBody Parser<LexerType>::parseFunctionBo template <typename LexerType> template <FunctionRequirements requirements, bool nameIsInContainingScope, class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuilder& context, const Identifier*& name, TreeFormalParameterList& parameters, TreeFunctionBody& body, int& openBracePos, int& closeBracePos, int& bodyStartLine) { - AutoPopScopeRef functionScope(this, pushScope(currentScope()->modeFlags() | FunctionModeFlag)); + AutoPopScopeRef functionScope(this, pushScope()); + functionScope->setIsFunction(); if (match(IDENT)) { name = m_token.m_data.ident; next(); @@ -794,8 +793,8 @@ template <FunctionRequirements requirements, bool nameIsInContainingScope, class // If we know about this function already, we can use the cached info and skip the parser to the end of the function. if (const SourceProviderCacheItem* cachedInfo = TreeBuilder::CanUseFunctionCache ? findCachedFunctionInfo(openBracePos) : 0) { // If we're in a strict context, the cached function info must say it was strict too. - ASSERT(!strictMode() || (cachedInfo->scopeFlags & StrictModeFlag)); - body = context.createFunctionBody(m_lexer->lastLineNumber(), cachedInfo->scopeFlags); + ASSERT(!strictMode() || cachedInfo->strictMode); + body = context.createFunctionBody(m_lexer->lastLineNumber(), cachedInfo->strictMode); functionScope->restoreFunctionInfo(cachedInfo); failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo)); @@ -855,8 +854,6 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseFunctionDecla failIfFalse((parseFunctionInfo<FunctionNeedsName, true>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine))); failIfFalse(name); failIfFalseIfStrict(declareVariable(name)); - if (*name == m_globalData->propertyNames->arguments) - currentScope()->setFlags(UsesArgumentsFlag); return context.createFuncDeclStatement(m_lexer->lastLineNumber(), name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine); } @@ -1416,18 +1413,13 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parsePrimaryExpre } case THISTOKEN: { next(); - currentScope()->setFlags(UsesThisFlag); return context.thisExpr(m_lexer->lastLineNumber()); } case IDENT: { int start = tokenStart(); const Identifier* ident = m_token.m_data.ident; next(); - if (m_globalData->propertyNames->eval == *ident) - currentScope()->setFlags(UsesEvalFlag); - else if (m_globalData->propertyNames->arguments == *ident) - currentScope()->setFlags(UsesArgumentsFlag); - currentScope()->useVariable(ident); + currentScope()->useVariable(ident, m_globalData->propertyNames->eval == *ident); m_lastIdentifier = ident; return context.createResolve(m_lexer->lastLineNumber(), ident, start); } diff --git a/Source/JavaScriptCore/parser/Parser.h b/Source/JavaScriptCore/parser/Parser.h index c0b13c53a..c2a11d665 100644 --- a/Source/JavaScriptCore/parser/Parser.h +++ b/Source/JavaScriptCore/parser/Parser.h @@ -130,19 +130,30 @@ struct ScopeLabelInfo { }; struct Scope { - Scope(const JSGlobalData* globalData, ScopeFlags scopeFlags) + Scope(const JSGlobalData* globalData, bool isFunction, bool strictMode) : m_globalData(globalData) - , m_scopeFlags(scopeFlags) + , m_shadowsArguments(false) + , m_usesEval(false) + , m_needsFullActivation(false) + , m_allowsNewDecls(true) + , m_strictMode(strictMode) + , m_isFunction(isFunction) + , m_isFunctionBoundary(false) , m_isValidStrictMode(true) , m_loopDepth(0) , m_switchDepth(0) { - ASSERT(!(scopeFlags & ~AllScopeModeFlags)); } Scope(const Scope& rhs) : m_globalData(rhs.m_globalData) - , m_scopeFlags(rhs.m_scopeFlags) + , m_shadowsArguments(rhs.m_shadowsArguments) + , m_usesEval(rhs.m_usesEval) + , m_needsFullActivation(rhs.m_needsFullActivation) + , m_allowsNewDecls(rhs.m_allowsNewDecls) + , m_strictMode(rhs.m_strictMode) + , m_isFunction(rhs.m_isFunction) + , m_isFunctionBoundary(rhs.m_isFunctionBoundary) , m_isValidStrictMode(rhs.m_isValidStrictMode) , m_loopDepth(rhs.m_loopDepth) , m_switchDepth(rhs.m_switchDepth) @@ -157,22 +168,6 @@ struct Scope { } } - ALWAYS_INLINE ScopeFlags scopeFlags() const { return m_scopeFlags; } - ALWAYS_INLINE ScopeFlags modeFlags() const { return m_scopeFlags & AllScopeModeFlags; } - ALWAYS_INLINE ScopeFlags usesFlags() const { return m_scopeFlags & AllScopeUsesFlags; } - ALWAYS_INLINE void setFlags(ScopeFlags scopeFlags) { m_scopeFlags |= scopeFlags; } - - ALWAYS_INLINE bool usesEval() const { return m_scopeFlags & UsesEvalFlag; } - ALWAYS_INLINE bool strictMode() const { return m_scopeFlags & StrictModeFlag; } - ALWAYS_INLINE bool shadowsArguments() const { return m_scopeFlags & ShadowsArgumentsFlag; } - ALWAYS_INLINE bool isFunction() const { return m_scopeFlags & FunctionModeFlag; } - ALWAYS_INLINE bool isBlockScope() const { return m_scopeFlags & BlockScopeFlag; } - ALWAYS_INLINE bool isFunctionBoundary() const { return isFunction() && !isBlockScope(); } - - ALWAYS_INLINE bool allowsNewDecls() const { return !isBlockScope(); } - - ALWAYS_INLINE bool isValidStrictMode() const { return m_isValidStrictMode; } - void startSwitch() { m_switchDepth++; } void endSwitch() { m_switchDepth--; } void startLoop() { m_loopDepth++; } @@ -206,6 +201,14 @@ struct Scope { return 0; } + void setIsFunction() + { + m_isFunction = true; + m_isFunctionBoundary = true; + } + bool isFunction() { return m_isFunction; } + bool isFunctionBoundary() { return m_isFunctionBoundary; } + bool declareVariable(const Identifier* ident) { bool isValidStrictMode = m_globalData->propertyNames->eval != *ident && m_globalData->propertyNames->arguments != *ident; @@ -216,28 +219,35 @@ struct Scope { void declareWrite(const Identifier* ident) { - ASSERT(strictMode()); + ASSERT(m_strictMode); m_writtenVariables.add(ident->impl()); } + void preventNewDecls() { m_allowsNewDecls = false; } + bool allowsNewDecls() const { return m_allowsNewDecls; } + bool declareParameter(const Identifier* ident) { bool isArguments = m_globalData->propertyNames->arguments == *ident; bool isValidStrictMode = m_declaredVariables.add(ident->ustring().impl()).isNewEntry && m_globalData->propertyNames->eval != *ident && !isArguments; m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode; if (isArguments) - setFlags(ShadowsArgumentsFlag); + m_shadowsArguments = true; return isValidStrictMode; } - void useVariable(const Identifier* ident) + void useVariable(const Identifier* ident, bool isEval) { + m_usesEval |= isEval; m_usedVariables.add(ident->ustring().impl()); } + void setNeedsFullActivation() { m_needsFullActivation = true; } + bool collectFreeVariables(Scope* nestedScope, bool shouldTrackClosedVariables) { - setFlags(nestedScope->usesFlags()); + if (nestedScope->m_usesEval) + m_usesEval = true; IdentifierSet::iterator end = nestedScope->m_usedVariables.end(); for (IdentifierSet::iterator ptr = nestedScope->m_usedVariables.begin(); ptr != end; ++ptr) { if (nestedScope->m_declaredVariables.contains(*ptr)) @@ -269,7 +279,7 @@ struct Scope { void getCapturedVariables(IdentifierSet& capturedVariables) { - if (usesEval()) { + if (m_needsFullActivation || m_usesEval) { capturedVariables.swap(m_declaredVariables); return; } @@ -279,6 +289,11 @@ struct Scope { capturedVariables.add(*ptr); } } + void setStrictMode() { m_strictMode = true; } + bool strictMode() const { return m_strictMode; } + bool isValidStrictMode() const { return m_isValidStrictMode; } + bool shadowsArguments() const { return m_shadowsArguments; } + void copyCapturedVariablesToVector(const IdentifierSet& capturedVariables, Vector<RefPtr<StringImpl> >& vector) { IdentifierSet::iterator end = capturedVariables.end(); @@ -292,16 +307,20 @@ struct Scope { void saveFunctionInfo(SourceProviderCacheItem* info) { - ASSERT(isFunction()); - info->scopeFlags = m_scopeFlags; + ASSERT(m_isFunction); + info->usesEval = m_usesEval; + info->strictMode = m_strictMode; + info->needsFullActivation = m_needsFullActivation; copyCapturedVariablesToVector(m_writtenVariables, info->writtenVariables); copyCapturedVariablesToVector(m_usedVariables, info->usedVariables); } void restoreFunctionInfo(const SourceProviderCacheItem* info) { - ASSERT(isFunction()); - m_scopeFlags |= info->scopeFlags; + ASSERT(m_isFunction); + m_usesEval = info->usesEval; + m_strictMode = info->strictMode; + m_needsFullActivation = info->needsFullActivation; unsigned size = info->usedVariables.size(); for (unsigned i = 0; i < size; ++i) m_usedVariables.add(info->usedVariables[i]); @@ -312,7 +331,13 @@ struct Scope { private: const JSGlobalData* m_globalData; - ScopeFlags m_scopeFlags; + bool m_shadowsArguments : 1; + bool m_usesEval : 1; + bool m_needsFullActivation : 1; + bool m_allowsNewDecls : 1; + bool m_strictMode : 1; + bool m_isFunction : 1; + bool m_isFunctionBoundary : 1; bool m_isValidStrictMode : 1; int m_loopDepth; int m_switchDepth; @@ -402,14 +427,20 @@ private: Parser* m_parser; }; - ALWAYS_INLINE ScopeRef currentScope() + ScopeRef currentScope() { return ScopeRef(&m_scopeStack, m_scopeStack.size() - 1); } - ScopeRef pushScope(ScopeFlags scopeFlags) + ScopeRef pushScope() { - m_scopeStack.append(Scope(m_globalData, scopeFlags)); + bool isFunction = false; + bool isStrict = false; + if (!m_scopeStack.isEmpty()) { + isStrict = m_scopeStack.last().strictMode(); + isFunction = m_scopeStack.last().isFunction(); + } + m_scopeStack.append(Scope(m_globalData, isFunction, isStrict)); return currentScope(); } @@ -461,7 +492,7 @@ private: UString parseInner(); void didFinishParsing(SourceElements*, ParserArenaData<DeclarationStacks::VarStack>*, - ParserArenaData<DeclarationStacks::FunctionStack>*, ScopeFlags, + ParserArenaData<DeclarationStacks::FunctionStack>*, CodeFeatures, int, int, IdentifierSet&); // Used to determine type of error to report. @@ -792,13 +823,14 @@ private: m_errorMessage = UString(msg); } - ALWAYS_INLINE void startLoop() { currentScope()->startLoop(); } - ALWAYS_INLINE void endLoop() { currentScope()->endLoop(); } - ALWAYS_INLINE void startSwitch() { currentScope()->startSwitch(); } - ALWAYS_INLINE void endSwitch() { currentScope()->endSwitch(); } - ALWAYS_INLINE bool strictMode() { return currentScope()->strictMode(); } - ALWAYS_INLINE bool isValidStrictMode() { return currentScope()->isValidStrictMode(); } - ALWAYS_INLINE bool declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); } + void startLoop() { currentScope()->startLoop(); } + void endLoop() { currentScope()->endLoop(); } + void startSwitch() { currentScope()->startSwitch(); } + void endSwitch() { currentScope()->endSwitch(); } + void setStrictMode() { currentScope()->setStrictMode(); } + bool strictMode() { return currentScope()->strictMode(); } + bool isValidStrictMode() { return currentScope()->isValidStrictMode(); } + bool declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); } bool breakIsValid() { ScopeRef current = currentScope(); @@ -917,7 +949,7 @@ private: ParserArenaData<DeclarationStacks::VarStack>* m_varDeclarations; ParserArenaData<DeclarationStacks::FunctionStack>* m_funcDeclarations; IdentifierSet m_capturedVariables; - ScopeFlags m_scopeFlags; + CodeFeatures m_features; int m_numConstants; struct DepthManager { @@ -978,7 +1010,7 @@ PassRefPtr<ParsedNode> Parser<LexerType>::parse(JSGlobalObject* lexicalGlobalObj m_funcDeclarations ? &m_funcDeclarations->data : 0, m_capturedVariables, *m_source, - m_scopeFlags, + m_features, m_numConstants); result->setLoc(m_source->firstLine(), m_lastLine); } else if (lexicalGlobalObject) { diff --git a/Source/JavaScriptCore/parser/SourceProviderCacheItem.h b/Source/JavaScriptCore/parser/SourceProviderCacheItem.h index ad7a759ce..3662367a0 100644 --- a/Source/JavaScriptCore/parser/SourceProviderCacheItem.h +++ b/Source/JavaScriptCore/parser/SourceProviderCacheItem.h @@ -61,7 +61,9 @@ public: int closeBraceLine; int closeBracePos; - unsigned short scopeFlags; + bool usesEval; + bool strictMode; + bool needsFullActivation; Vector<RefPtr<StringImpl> > usedVariables; Vector<RefPtr<StringImpl> > writtenVariables; }; diff --git a/Source/JavaScriptCore/parser/SyntaxChecker.h b/Source/JavaScriptCore/parser/SyntaxChecker.h index 2acb5097d..c2c93756d 100644 --- a/Source/JavaScriptCore/parser/SyntaxChecker.h +++ b/Source/JavaScriptCore/parser/SyntaxChecker.h @@ -220,6 +220,7 @@ public: void appendStatement(int, int) { } void addVar(const Identifier*, bool) { } int combineCommaNodes(int, int, int) { return 1; } + int evalCount() const { return 0; } void appendBinaryExpressionInfo(int& operandStackDepth, int expr, int, int, int, bool) { if (!m_topBinaryExpr) diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp index 934533c46..3690c2c33 100644 --- a/Source/JavaScriptCore/runtime/Executable.cpp +++ b/Source/JavaScriptCore/runtime/Executable.cpp @@ -225,7 +225,7 @@ JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scope ASSERT(exception); return exception; } - recordParse(evalNode->scopeFlags(), evalNode->hasCapturedVariables(), evalNode->lineNo(), evalNode->lastLine()); + recordParse(evalNode->features(), evalNode->hasCapturedVariables(), evalNode->lineNo(), evalNode->lastLine()); JSGlobalObject* globalObject = scopeChainNode->globalObject.get(); @@ -357,7 +357,7 @@ JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* sc ASSERT(exception); return exception; } - recordParse(programNode->scopeFlags(), programNode->hasCapturedVariables(), programNode->lineNo(), programNode->lastLine()); + recordParse(programNode->features(), programNode->hasCapturedVariables(), programNode->lineNo(), programNode->lastLine()); JSGlobalObject* globalObject = scopeChainNode->globalObject.get(); @@ -512,7 +512,7 @@ PassOwnPtr<FunctionCodeBlock> FunctionExecutable::produceCodeBlockFor(ScopeChain if (m_forceUsesArguments) body->setUsesArguments(); body->finishParsing(m_parameters, m_name); - recordParse(body->scopeFlags(), body->hasCapturedVariables(), body->lineNo(), body->lastLine()); + recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine()); OwnPtr<FunctionCodeBlock> result; ASSERT((compilationKind == FirstCompilation) == !codeBlockFor(specializationKind)); diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h index 3b979ba82..b9d3e6ee1 100644 --- a/Source/JavaScriptCore/runtime/Executable.h +++ b/Source/JavaScriptCore/runtime/Executable.h @@ -271,14 +271,14 @@ namespace JSC { ScriptExecutable(Structure* structure, JSGlobalData& globalData, const SourceCode& source, bool isInStrictContext) : ExecutableBase(globalData, structure, NUM_PARAMETERS_NOT_COMPILED) , m_source(source) - , m_scopeFlags(isInStrictContext ? StrictModeFlag : NoScopeFlags) + , m_features(isInStrictContext ? StrictModeFeature : 0) { } ScriptExecutable(Structure* structure, ExecState* exec, const SourceCode& source, bool isInStrictContext) : ExecutableBase(exec->globalData(), structure, NUM_PARAMETERS_NOT_COMPILED) , m_source(source) - , m_scopeFlags(isInStrictContext ? StrictModeFlag : NoScopeFlags) + , m_features(isInStrictContext ? StrictModeFeature : 0) { } @@ -292,10 +292,10 @@ namespace JSC { int lineNo() const { return m_firstLine; } int lastLine() const { return m_lastLine; } - bool usesEval() const { return m_scopeFlags & UsesEvalFlag; } - bool usesArguments() const { return m_scopeFlags & UsesArgumentsFlag; } - bool needsActivation() const { return m_hasCapturedVariables || m_scopeFlags & (UsesEvalFlag | UsesWithFlag | UsesCatchFlag); } - bool isStrictMode() const { return m_scopeFlags & StrictModeFlag; } + bool usesEval() const { return m_features & EvalFeature; } + bool usesArguments() const { return m_features & ArgumentsFeature; } + bool needsActivation() const { return m_hasCapturedVariables || m_features & (EvalFeature | WithFeature | CatchFeature); } + bool isStrictMode() const { return m_features & StrictModeFeature; } void unlinkCalls(); @@ -311,16 +311,16 @@ namespace JSC { #endif } - void recordParse(ScopeFlags scopeFlags, bool hasCapturedVariables, int firstLine, int lastLine) + void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine) { - m_scopeFlags = scopeFlags; + m_features = features; m_hasCapturedVariables = hasCapturedVariables; m_firstLine = firstLine; m_lastLine = lastLine; } SourceCode m_source; - ScopeFlags m_scopeFlags; + CodeFeatures m_features; bool m_hasCapturedVariables; int m_firstLine; int m_lastLine; diff --git a/Source/JavaScriptCore/runtime/JSFunction.cpp b/Source/JavaScriptCore/runtime/JSFunction.cpp index 243946ba9..563325ab0 100644 --- a/Source/JavaScriptCore/runtime/JSFunction.cpp +++ b/Source/JavaScriptCore/runtime/JSFunction.cpp @@ -112,6 +112,16 @@ void JSFunction::finishCreation(ExecState* exec, FunctionExecutable* executable, putDirectOffset(exec->globalData(), scopeChainNode->globalObject->functionNameOffset(), executable->nameValue()); } +Structure* JSFunction::cacheInheritorID(ExecState* exec) +{ + JSValue prototype = get(exec, exec->globalData().propertyNames->prototype); + if (prototype.isObject()) + m_cachedInheritorID.set(exec->globalData(), this, asObject(prototype)->inheritorID(exec->globalData())); + else + m_cachedInheritorID.set(exec->globalData(), this, globalObject()->emptyObjectStructure()); + return m_cachedInheritorID.get(); +} + const UString& JSFunction::name(ExecState* exec) { return asString(getDirect(exec->globalData(), exec->globalData().propertyNames->name))->tryGetValue(); @@ -332,6 +342,7 @@ void JSFunction::put(JSCell* cell, ExecState* exec, const Identifier& propertyNa // following the rules set out in ECMA-262 8.12.9. PropertySlot slot; thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot); + thisObject->m_cachedInheritorID.clear(); } if (thisObject->jsExecutable()->isStrictMode() && (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().caller)) { // This will trigger the property to be reified, if this is not already the case! @@ -372,6 +383,7 @@ bool JSFunction::defineOwnProperty(JSObject* object, ExecState* exec, const Iden // following the rules set out in ECMA-262 8.12.9. PropertySlot slot; thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot); + thisObject->m_cachedInheritorID.clear(); return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException); } diff --git a/Source/JavaScriptCore/runtime/JSFunction.h b/Source/JavaScriptCore/runtime/JSFunction.h index 5553115bf..9de66d721 100644 --- a/Source/JavaScriptCore/runtime/JSFunction.h +++ b/Source/JavaScriptCore/runtime/JSFunction.h @@ -121,6 +121,18 @@ namespace JSC { return OBJECT_OFFSETOF(JSFunction, m_executable); } + Structure* cachedInheritorID(ExecState* exec) + { + if (UNLIKELY(!m_cachedInheritorID)) + return cacheInheritorID(exec); + return m_cachedInheritorID.get(); + } + + static size_t offsetOfCachedInheritorID() + { + return OBJECT_OFFSETOF(JSFunction, m_cachedInheritorID); + } + protected: const static unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags; @@ -130,6 +142,8 @@ namespace JSC { void finishCreation(ExecState*, NativeExecutable*, int length, const Identifier& name); void finishCreation(ExecState*, FunctionExecutable*, ScopeChainNode*); + Structure* cacheInheritorID(ExecState*); + static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&); static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&); static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode = ExcludeDontEnumProperties); @@ -152,6 +166,7 @@ namespace JSC { WriteBarrier<ExecutableBase> m_executable; WriteBarrier<ScopeChainNode> m_scopeChain; + WriteBarrier<Structure> m_cachedInheritorID; }; inline bool JSValue::isFunction() const diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp index 500f3891a..a8c6c3f3f 100644 --- a/Source/JavaScriptCore/runtime/JSObject.cpp +++ b/Source/JavaScriptCore/runtime/JSObject.cpp @@ -552,7 +552,7 @@ Structure* JSObject::createInheritorID(JSGlobalData& globalData) return m_inheritorID.get(); } -PropertyStorage JSObject::growPropertyStorage(JSGlobalData& globalData, size_t oldSize, size_t newSize) +void JSObject::allocatePropertyStorage(JSGlobalData& globalData, size_t oldSize, size_t newSize) { ASSERT(newSize > oldSize); @@ -580,7 +580,7 @@ PropertyStorage JSObject::growPropertyStorage(JSGlobalData& globalData, size_t o } ASSERT(newPropertyStorage); - return newPropertyStorage; + m_propertyStorage.set(globalData, this, newPropertyStorage); } bool JSObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h index d95860d62..7345bb700 100644 --- a/Source/JavaScriptCore/runtime/JSObject.h +++ b/Source/JavaScriptCore/runtime/JSObject.h @@ -212,9 +212,8 @@ namespace JSC { bool staticFunctionsReified() { return structure()->staticFunctionsReified(); } void reifyStaticFunctionsForDelete(ExecState* exec); - JS_EXPORT_PRIVATE PropertyStorage growPropertyStorage(JSGlobalData&, size_t oldSize, size_t newSize); + JS_EXPORT_PRIVATE void allocatePropertyStorage(JSGlobalData&, size_t oldSize, size_t newSize); bool isUsingInlineStorage() const { return static_cast<const void*>(m_propertyStorage.get()) == static_cast<const void*>(this + 1); } - void setPropertyStorage(JSGlobalData&, PropertyStorage, Structure*); void* addressOfPropertyStorage() { @@ -453,14 +452,6 @@ inline bool JSObject::isGlobalThis() const return structure()->typeInfo().type() == GlobalThisType; } -inline void JSObject::setPropertyStorage(JSGlobalData& globalData, PropertyStorage storage, Structure* structure) -{ - ASSERT(storage); - ASSERT(structure); - setStructure(globalData, structure); - m_propertyStorage.set(globalData, this, storage); -} - inline JSObject* constructEmptyObject(ExecState* exec, Structure* structure) { return JSFinalObject::create(exec, structure); @@ -672,11 +663,10 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi if ((mode == PutModePut) && !isExtensible()) return false; - PropertyStorage newStorage = propertyStorage(); - if (structure()->shouldGrowPropertyStorage()) - newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), structure()->suggestedNewPropertyStorageSize()); + size_t currentCapacity = structure()->propertyStorageCapacity(); offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, specificFunction); - setPropertyStorage(globalData, newStorage, structure()); + if (currentCapacity != structure()->propertyStorageCapacity()) + allocatePropertyStorage(globalData, currentCapacity, structure()->propertyStorageCapacity()); ASSERT(offset < structure()->propertyStorageCapacity()); putDirectOffset(globalData, offset, value); @@ -688,13 +678,12 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi size_t offset; size_t currentCapacity = structure()->propertyStorageCapacity(); - if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName, attributes, specificFunction, offset)) { - PropertyStorage newStorage = propertyStorage(); + if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName, attributes, specificFunction, offset)) { if (currentCapacity != structure->propertyStorageCapacity()) - newStorage = growPropertyStorage(globalData, currentCapacity, structure->propertyStorageCapacity()); + allocatePropertyStorage(globalData, currentCapacity, structure->propertyStorageCapacity()); ASSERT(offset < structure->propertyStorageCapacity()); - setPropertyStorage(globalData, newStorage, structure); + setStructure(globalData, structure); putDirectOffset(globalData, offset, value); // This is a new property; transitions with specific values are not currently cachable, // so leave the slot in an uncachable state. @@ -738,14 +727,13 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi if ((mode == PutModePut) && !isExtensible()) return false; - PropertyStorage newStorage = propertyStorage(); - if (structure()->shouldGrowPropertyStorage()) - newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), structure()->suggestedNewPropertyStorageSize()); - Structure* structure = Structure::addPropertyTransition(globalData, this->structure(), propertyName, attributes, specificFunction, offset); + if (currentCapacity != structure->propertyStorageCapacity()) + allocatePropertyStorage(globalData, currentCapacity, structure->propertyStorageCapacity()); + ASSERT(offset < structure->propertyStorageCapacity()); - setPropertyStorage(globalData, newStorage, structure); + setStructure(globalData, structure); putDirectOffset(globalData, offset, value); // This is a new property; transitions with specific values are not currently cachable, // so leave the slot in an uncachable state. @@ -779,20 +767,18 @@ inline void JSObject::putDirect(JSGlobalData& globalData, const Identifier& prop inline void JSObject::putDirectWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes) { ASSERT(!value.isGetterSetter() && !(attributes & Accessor)); - PropertyStorage newStorage = propertyStorage(); - if (structure()->shouldGrowPropertyStorage()) - newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), structure()->suggestedNewPropertyStorageSize()); + size_t currentCapacity = structure()->propertyStorageCapacity(); size_t offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, getJSFunction(value)); - setPropertyStorage(globalData, newStorage, structure()); + if (currentCapacity != structure()->propertyStorageCapacity()) + allocatePropertyStorage(globalData, currentCapacity, structure()->propertyStorageCapacity()); putDirectOffset(globalData, offset, value); } inline void JSObject::transitionTo(JSGlobalData& globalData, Structure* newStructure) { - PropertyStorage newStorage = propertyStorage(); if (structure()->propertyStorageCapacity() != newStructure->propertyStorageCapacity()) - newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), newStructure->propertyStorageCapacity()); - setPropertyStorage(globalData, newStorage, newStructure); + allocatePropertyStorage(globalData, structure()->propertyStorageCapacity(), newStructure->propertyStorageCapacity()); + setStructure(globalData, newStructure); } inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const diff --git a/Source/JavaScriptCore/runtime/JSString.h b/Source/JavaScriptCore/runtime/JSString.h index 10ec799e5..c95233deb 100644 --- a/Source/JavaScriptCore/runtime/JSString.h +++ b/Source/JavaScriptCore/runtime/JSString.h @@ -67,6 +67,7 @@ namespace JSC { friend class JSGlobalData; friend class SpecializedThunkJIT; friend class JSRopeString; + friend class MarkStack; friend struct ThunkHelpers; typedef JSCell Base; @@ -91,6 +92,7 @@ namespace JSC { Base::finishCreation(globalData); m_length = length; m_is8Bit = m_value.impl()->is8Bit(); + m_isHashConstSingleton = false; } void finishCreation(JSGlobalData& globalData, size_t length, size_t cost) @@ -99,6 +101,7 @@ namespace JSC { Base::finishCreation(globalData); m_length = length; m_is8Bit = m_value.impl()->is8Bit(); + m_isHashConstSingleton = false; Heap::heap(this)->reportExtraMemoryCost(cost); } @@ -108,6 +111,7 @@ namespace JSC { Base::finishCreation(globalData); m_length = 0; m_is8Bit = true; + m_isHashConstSingleton = false; } public: @@ -161,9 +165,13 @@ namespace JSC { protected: bool isRope() const { return m_value.isNull(); } bool is8Bit() const { return m_is8Bit; } + bool isHashConstSingleton() const { return m_isHashConstSingleton; } + void clearHashConstSingleton() { m_isHashConstSingleton = false; } + void setHashConstSingleton() { m_isHashConstSingleton = true; } // A string is represented either by a UString or a rope of fibers. bool m_is8Bit : 1; + bool m_isHashConstSingleton : 1; unsigned m_length; mutable UString m_value; @@ -233,6 +241,7 @@ namespace JSC { Base::finishCreation(globalData); m_length = s1->length() + s2->length(); m_is8Bit = (s1->is8Bit() && s2->is8Bit()); + m_isHashConstSingleton = false; m_fibers[0].set(globalData, this, s1); m_fibers[1].set(globalData, this, s2); } @@ -242,6 +251,7 @@ namespace JSC { Base::finishCreation(globalData); m_length = s1->length() + s2->length() + s3->length(); m_is8Bit = (s1->is8Bit() && s2->is8Bit() && s3->is8Bit()); + m_isHashConstSingleton = false; m_fibers[0].set(globalData, this, s1); m_fibers[1].set(globalData, this, s2); m_fibers[2].set(globalData, this, s3); diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp index 074c8b354..ac4b4f1fe 100644 --- a/Source/JavaScriptCore/runtime/Structure.cpp +++ b/Source/JavaScriptCore/runtime/Structure.cpp @@ -267,13 +267,6 @@ void Structure::growPropertyStorageCapacity() m_propertyStorageCapacity *= 2; } -size_t Structure::suggestedNewPropertyStorageSize() -{ - if (isUsingInlineStorage()) - return JSObject::baseExternalStorageCapacity; - return m_propertyStorageCapacity * 2; -} - void Structure::despecifyDictionaryFunction(JSGlobalData& globalData, const Identifier& propertyName) { StringImpl* rep = propertyName.impl(); diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h index 00bc76177..ee580e245 100644 --- a/Source/JavaScriptCore/runtime/Structure.h +++ b/Source/JavaScriptCore/runtime/Structure.h @@ -102,8 +102,6 @@ namespace JSC { bool isFrozen(JSGlobalData&); bool isExtensible() const { return !m_preventExtensions; } bool didTransition() const { return m_didTransition; } - bool shouldGrowPropertyStorage() { return propertyStorageCapacity() == propertyStorageSize(); } - JS_EXPORT_PRIVATE size_t suggestedNewPropertyStorageSize(); Structure* flattenDictionaryStructure(JSGlobalData&, JSObject*); |