diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2012-09-24 13:09:44 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@digia.com> | 2012-09-24 13:09:44 +0200 |
commit | dc6262b587c71c14e30d93e57ed812e36a79a33e (patch) | |
tree | 03ff986e7aa38bba0c0ef374f44fda52aff93f01 /Source/JavaScriptCore | |
parent | 02e1fbbefd49229b102ef107bd70ce974a2d85fb (diff) | |
download | qtwebkit-dc6262b587c71c14e30d93e57ed812e36a79a33e.tar.gz |
Imported WebKit commit 6339232fec7f5d9984a33388aecfd2cbc7832053 (http://svn.webkit.org/repository/webkit/trunk@129343)
New snapshot with build fixes for latest qtbase
Diffstat (limited to 'Source/JavaScriptCore')
72 files changed, 1346 insertions, 564 deletions
diff --git a/Source/JavaScriptCore/API/JSCallbackObject.h b/Source/JavaScriptCore/API/JSCallbackObject.h index 8d7aedd3e..5022aaf40 100644 --- a/Source/JavaScriptCore/API/JSCallbackObject.h +++ b/Source/JavaScriptCore/API/JSCallbackObject.h @@ -186,7 +186,7 @@ private: static bool deleteProperty(JSCell*, ExecState*, PropertyName); static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned); - static bool hasInstance(JSObject*, ExecState*, JSValue, JSValue proto); + static bool customHasInstance(JSObject*, ExecState*, JSValue); static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); diff --git a/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h b/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h index 39d078239..688e7b8b9 100644 --- a/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h +++ b/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h @@ -389,7 +389,7 @@ EncodedJSValue JSCallbackObject<Parent>::construct(ExecState* exec) } template <class Parent> -bool JSCallbackObject<Parent>::hasInstance(JSObject* object, ExecState* exec, JSValue value, JSValue) +bool JSCallbackObject<Parent>::customHasInstance(JSObject* object, ExecState* exec, JSValue value) { JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(object); JSContextRef execRef = toRef(exec); diff --git a/Source/JavaScriptCore/API/JSValueRef.cpp b/Source/JavaScriptCore/API/JSValueRef.cpp index 4c986c253..bb92454bd 100644 --- a/Source/JavaScriptCore/API/JSValueRef.cpp +++ b/Source/JavaScriptCore/API/JSValueRef.cpp @@ -175,7 +175,7 @@ bool JSValueIsInstanceOfConstructor(JSContextRef ctx, JSValueRef value, JSObject JSObject* jsConstructor = toJS(constructor); if (!jsConstructor->structure()->typeInfo().implementsHasInstance()) return false; - bool result = jsConstructor->methodTable()->hasInstance(jsConstructor, exec, jsValue, jsConstructor->get(exec, exec->propertyNames().prototype)); // false if an exception is thrown + bool result = jsConstructor->hasInstance(exec, jsValue); // false if an exception is thrown if (exec->hadException()) { if (exception) *exception = toRef(exec, exec->exception()); diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog index ca7100e21..5d81031ba 100644 --- a/Source/JavaScriptCore/ChangeLog +++ b/Source/JavaScriptCore/ChangeLog @@ -1,3 +1,595 @@ +2012-09-23 Geoffrey Garen <ggaren@apple.com> + + PutScopedVar should not be marked as clobbering the world + https://bugs.webkit.org/show_bug.cgi?id=97416 + + Reviewed by Filip Pizlo. + + No performance change. + + PutScopedVar doesn't have arbitrary side-effects, so it shouldn't be marked + as such. + + * dfg/DFGNodeType.h: + (DFG): + +2012-09-23 Geoffrey Garen <ggaren@apple.com> + + I accidentally the whole 32-bit :(. + + Unbreak the DFG in 32-bit with the 32-bit path I forgot in my last patch. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + +2012-09-23 Byungwoo Lee <bw80.lee@gmail.com> + + Fix build warnings : -Wunused-parameter, -Wparentheses, -Wuninitialized. + https://bugs.webkit.org/show_bug.cgi?id=97306 + + Reviewed by Benjamin Poulain. + + Fix build warning about -Wunused-parameter on MachineStackMarker.cpp, + LLIntSlowPaths.cpp, DatePrototype.cpp, Options.cpp by using + UNUSED_PARAM() macro or remove parameter name. + + * heap/MachineStackMarker.cpp: + (JSC::pthreadSignalHandlerSuspendResume): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::entryOSR): + * runtime/DatePrototype.cpp: + (JSC::formatLocaleDate): + * runtime/Options.cpp: + (JSC::computeNumberOfGCMarkers): + +2012-09-23 Gavin Barraclough <barraclough@apple.com> + + Sorting a non-array creates propreties (spec-violation) + https://bugs.webkit.org/show_bug.cgi?id=25477 + + Reviewed by Oliver Hunt. + + We're just calling get() to get properties, which is converting missing properties to + undefined. Hole values should be retained, and moved to the end of the array. + + * runtime/ArrayPrototype.cpp: + (JSC::getOrHole): + - Helper function, returns JSValue() instead of undefined for missing properties. + (JSC::arrayProtoFuncSort): + - Implemented per 15.4.4.11, see comments above. + +2012-09-23 Geoffrey Garen <ggaren@apple.com> + + CSE for access to closure variables (get_/put_scoped_var) + https://bugs.webkit.org/show_bug.cgi?id=97414 + + Reviewed by Oliver Hunt. + + I separated loading a scope from loading its storage pointer, so we can + CSE the storage pointer load. Then, I copied the global var CSE and adjusted + it for closure vars. + + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::execute): Renamed GetScopeChain => GetScope to + reflect renames from a few weeks ago. + + Added a case for the storage pointer load, similar to object storage pointer load. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): Added an independent node for + the storage pointer. + + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::scopedVarLoadElimination): + (CSEPhase): + (JSC::DFG::CSEPhase::scopedVarStoreElimination): + (JSC::DFG::CSEPhase::getScopeLoadElimination): + (JSC::DFG::CSEPhase::getScopeRegistersLoadElimination): + (JSC::DFG::CSEPhase::setLocalStoreElimination): + (JSC::DFG::CSEPhase::performNodeCSE): Copied globalVarLoad/StoreElimination + and adapted the same logic to closure vars. + + * dfg/DFGNode.h: + (JSC::DFG::Node::hasScopeChainDepth): + (JSC::DFG::Node::scope): + (Node): + * dfg/DFGNodeType.h: + (DFG): GetScopedVar and GetGlobalVar are no longer MustGenerate. I'm not + sure why they ever were. But these are simple load operations so, if they're + unused, they're truly dead. + + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): Updated for renames and split-out + node for getting the storage pointer. + +2012-09-21 Geoffrey Garen <ggaren@apple.com> + + Unreviewed, rolled out a line I committed by accident. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): + +2012-09-21 Geoffrey Garen <ggaren@apple.com> + + Optimized closures that capture arguments + https://bugs.webkit.org/show_bug.cgi?id=97358 + + Reviewed by Oliver Hunt. + + Previously, the activation object was responsible for capturing all + arguments in a way that was convenient for the arguments object. Now, + we move all captured variables into a contiguous region in the stack, + allocate an activation for exactly that size, and make the arguments + object responsible for knowing all the places to which arguments could + have moved. + + This seems like the right tradeoff because + + (a) Closures are common and long-lived, so we want them to be small. + + (b) Our primary strategy for optimizing the arguments object is to make + it go away. If you're allocating arguments objects, you're already having + a bad time. + + (c) It's common to use either the arguments object or named argument + closure, but not both. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + (JSC::CodeBlock::CodeBlock): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::argumentsRegister): + (JSC::CodeBlock::activationRegister): + (JSC::CodeBlock::isCaptured): + (JSC::CodeBlock::argumentIndexAfterCapture): m_numCapturedVars is gone + now -- we have an explicit range instead. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): Move captured arguments + into the captured region of local variables for space efficiency. Record + precise data about where they moved for the sake of the arguments object. + + Some of this data was previously wrong, but it didn't cause any problems + because the arguments weren't actually moving. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::flushArgumentsAndCapturedVariables): Don't + assume that captured vars are in any particular location -- always ask + the CodeBlock. This is better encapsulation. + + (JSC::DFG::ByteCodeParser::parseCodeBlock): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): I rename things sometimes. + + * runtime/Arguments.cpp: + (JSC::Arguments::tearOff): Account for a particularly nasty edge case. + + (JSC::Arguments::didTearOffActivation): Don't allocate our slow arguments + data on tear-off. We need to allocate it eagerly instead, since we need + to know about displaced, captured arguments during access before tear-off. + + * runtime/Arguments.h: + (JSC::Arguments::allocateSlowArguments): + (JSC::Arguments::argument): Tell our slow arguments array where all arguments + are, even if they are not captured. This simplifies some things, so we don't + have to account explicitly for the full matrix of (not torn off, torn off) + * (captured, not captured). + + (JSC::Arguments::finishCreation): Allocate our slow arguments array eagerly + because we need to know about displaced, captured arguments during access + before tear-off. + + * runtime/Executable.cpp: + (JSC::FunctionExecutable::FunctionExecutable): + (JSC::FunctionExecutable::compileForCallInternal): + (JSC::FunctionExecutable::compileForConstructInternal): + * runtime/Executable.h: + (JSC::FunctionExecutable::parameterCount): + (FunctionExecutable): + * runtime/JSActivation.cpp: + (JSC::JSActivation::visitChildren): + * runtime/JSActivation.h: + (JSActivation): + (JSC::JSActivation::create): + (JSC::JSActivation::JSActivation): + (JSC::JSActivation::registerOffset): + (JSC::JSActivation::tearOff): + (JSC::JSActivation::allocationSize): + (JSC::JSActivation::isValid): This is really the point of the patch. All + the pointer math in Activations basically boils away, since we always + copy a contiguous region of captured variables now. + + * runtime/SymbolTable.h: + (JSC::SlowArgument::SlowArgument): + (SlowArgument): + (SharedSymbolTable): + (JSC::SharedSymbolTable::captureCount): + (JSC::SharedSymbolTable::SharedSymbolTable): AllOfTheThings capture mode + is gone now -- that's the point of the patch. indexIfCaptured gets renamed + to index because we always have an index, even if not captured. (The only + time when the index is meaningless is when we're Deleted.) + +2012-09-21 Gavin Barraclough <barraclough@apple.com> + + Eeeep - broke early boyer in bug#97382 + https://bugs.webkit.org/show_bug.cgi?id=97383 + + Rubber stamped by Sam Weinig. + + missed a child3 -> child2! + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileInstanceOf): + +2012-09-21 Gavin Barraclough <barraclough@apple.com> + + Unreviewed windows build fix. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + +2012-09-21 Gavin Barraclough <barraclough@apple.com> + + Pedantic test in Mozilla's JavaScript test suite fails. function-001.js function-001-n.js + https://bugs.webkit.org/show_bug.cgi?id=27219 + + Reviewed by Sam Weinig. + + These tests are just wrong. + See ECMA 262 A.5, FunctionDelcaration does not require a semicolon. + + * tests/mozilla/expected.html: + * tests/mozilla/js1_2/function/function-001-n.js: + * tests/mozilla/js1_3/Script/function-001-n.js: + * tests/mozilla/js1_3/regress/function-001-n.js: + +2012-09-21 Gavin Barraclough <barraclough@apple.com> + + Remove redundant argument to op_instanceof + https://bugs.webkit.org/show_bug.cgi?id=97382 + + Reviewed by Geoff Garen. + + No longer needed after my last change. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + * bytecode/Opcode.h: + (JSC): + (JSC::padOpcodeName): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitInstanceOf): + * bytecompiler/BytecodeGenerator.h: + (BytecodeGenerator): + * bytecompiler/NodesCodegen.cpp: + (JSC::InstanceOfNode::emitBytecode): + * dfg/DFGAbstractState.cpp: + (JSC::DFG::AbstractState::execute): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileInstanceOf): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_instanceof): + (JSC::JIT::emitSlow_op_instanceof): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_instanceof): + (JSC::JIT::emitSlow_op_instanceof): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + +2012-09-21 Gavin Barraclough <barraclough@apple.com> + + Unreviewed windows build fix. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + +2012-09-21 Gavin Barraclough <barraclough@apple.com> + + instanceof should not get the prototype for non-default HasInstance + https://bugs.webkit.org/show_bug.cgi?id=68656 + + Reviewed by Oliver Hunt. + + Instanceof is currently implemented as a sequance of three opcodes: + check_has_instance + get_by_id(prototype) + op_instanceof + There are three interesting types of base value that instanceof can be applied to: + (A) Objects supporting default instanceof behaviour (functions, other than those created with bind) + (B) Objects overriding the default instancecof behaviour with a custom one (API objects, bound functions) + (C) Values that do not respond to the [[HasInstance]] trap. + Currently check_has_instance handles case (C), leaving the op_instanceof opcode to handle (A) & (B). There are + two problems with this apporach. Firstly, this is suboptimal for case (A), since we have to check for + hasInstance support twice (once in check_has_instance, then for default behaviour in op_instanceof). Secondly, + this means that in cases (B) we also perform the get_by_id, which is both suboptimal and an observable spec + violation. + + The fix here is to move handing of non-default instanceof (cases (B)) to the check_has_instance op, leaving + op_instanceof to handle only cases (A). + + * API/JSCallbackObject.h: + (JSCallbackObject): + * API/JSCallbackObjectFunctions.h: + (JSC::::customHasInstance): + * API/JSValueRef.cpp: + (JSValueIsInstanceOfConstructor): + - renamed hasInstance to customHasInstance + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + - added additional parameters to check_has_instance opcode + * bytecode/Opcode.h: + (JSC): + (JSC::padOpcodeName): + - added additional parameters to check_has_instance opcode + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitCheckHasInstance): + - added additional parameters to check_has_instance opcode + * bytecompiler/BytecodeGenerator.h: + (BytecodeGenerator): + - added additional parameters to check_has_instance opcode + * bytecompiler/NodesCodegen.cpp: + (JSC::InstanceOfNode::emitBytecode): + - added additional parameters to check_has_instance opcode + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + - added additional parameters to check_has_instance opcode + * interpreter/Interpreter.cpp: + (JSC::isInvalidParamForIn): + (JSC::Interpreter::privateExecute): + - Add handling for non-default instanceof to op_check_has_instance + * jit/JITInlineMethods.h: + (JSC::JIT::emitArrayProfilingSiteForBytecodeIndex): + - Fixed no-LLInt no_DFG build + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_check_has_instance): + (JSC::JIT::emitSlow_op_check_has_instance): + - check for ImplementsDefaultHasInstance, handle additional arguments to op_check_has_instance. + (JSC::JIT::emit_op_instanceof): + (JSC::JIT::emitSlow_op_instanceof): + - no need to check for ImplementsDefaultHasInstance. + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_check_has_instance): + (JSC::JIT::emitSlow_op_check_has_instance): + - check for ImplementsDefaultHasInstance, handle additional arguments to op_check_has_instance. + (JSC::JIT::emit_op_instanceof): + (JSC::JIT::emitSlow_op_instanceof): + - no need to check for ImplementsDefaultHasInstance. + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * jit/JITStubs.h: + - Add handling for non-default instanceof to op_check_has_instance + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + - move check for ImplementsDefaultHasInstance, handle additional arguments to op_check_has_instance. + * runtime/ClassInfo.h: + (MethodTable): + (JSC): + - renamed hasInstance to customHasInstance + * runtime/CommonSlowPaths.h: + (CommonSlowPaths): + - removed opInstanceOfSlow (this was whittled down to one function call!) + * runtime/JSBoundFunction.cpp: + (JSC::JSBoundFunction::customHasInstance): + * runtime/JSBoundFunction.h: + (JSBoundFunction): + - renamed hasInstance to customHasInstance, reimplemented. + * runtime/JSCell.cpp: + (JSC::JSCell::customHasInstance): + * runtime/JSCell.h: + (JSCell): + * runtime/JSObject.cpp: + (JSC::JSObject::hasInstance): + (JSC): + (JSC::JSObject::defaultHasInstance): + * runtime/JSObject.h: + (JSObject): + +2012-09-21 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, fix ARM build. + + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::store8): + (MacroAssemblerARMv7): + * offlineasm/armv7.rb: + +2012-09-21 Filip Pizlo <fpizlo@apple.com> + + REGRESSION (r128400): Opening Google Web Fonts page hangs or crashes + https://bugs.webkit.org/show_bug.cgi?id=97328 + + Reviewed by Mark Hahnenberg. + + It's a bad idea to emit stub code that reallocates property storage when we're in indexed + storage mode. DFGRepatch.cpp knew this and had the appropriate check in one of the places, + but it didn't have it in all of the places. + + This change also adds some more handy disassembly support, which I used to find the bug. + + * assembler/LinkBuffer.h: + (JSC): + * dfg/DFGRepatch.cpp: + (JSC::DFG::generateProtoChainAccessStub): + (JSC::DFG::tryCacheGetByID): + (JSC::DFG::tryBuildGetByIDList): + (JSC::DFG::emitPutReplaceStub): + (JSC::DFG::emitPutTransitionStub): + (JSC::DFG::tryCachePutByID): + * jit/JITStubRoutine.h: + (JSC): + +2012-09-21 Filip Pizlo <fpizlo@apple.com> + + DFG CSE assumes that a holy PutByVal does not interfere with GetArrayLength, when it clearly does + https://bugs.webkit.org/show_bug.cgi?id=97373 + + Reviewed by Mark Hahnenberg. + + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::pureCSE): + (JSC::DFG::CSEPhase::getArrayLengthElimination): + (JSC::DFG::CSEPhase::putStructureStoreElimination): + (JSC::DFG::CSEPhase::performNodeCSE): + * dfg/DFGGraph.h: + (Graph): + +2012-09-21 Chris Rogers <crogers@google.com> + + Add Web Audio support for deprecated/legacy APIs + https://bugs.webkit.org/show_bug.cgi?id=97050 + + Reviewed by Eric Carlson. + + * Configurations/FeatureDefines.xcconfig: + +2012-09-21 Gavin Barraclough <barraclough@apple.com> + + Global Math object should be configurable but isn't + https://bugs.webkit.org/show_bug.cgi?id=55343 + + Reviewed by Oliver Hunt. + + This has no performance impact. + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::reset): + - Make 'Math' a regular property. + +2012-09-21 Chao-ying Fu <fu@mips.com> + + Add MIPS or32 function + https://bugs.webkit.org/show_bug.cgi?id=97157 + + Reviewed by Gavin Barraclough. + + Add a missing or32 function. + + * assembler/MacroAssemblerMIPS.h: + (JSC::MacroAssemblerMIPS::or32): New function. + (MacroAssemblerMIPS): + +2012-09-20 Filip Pizlo <fpizlo@apple.com> + + CHECK_ARRAY_CONSISTENCY isn't being used or tested, so we should remove it + https://bugs.webkit.org/show_bug.cgi?id=97260 + + Rubber stamped by Geoffrey Garen. + + Supporting it will become difficult as we add more indexing types. It makes more + sense to kill, especially since we don't appear to use it or test it, ever. + + * runtime/ArrayConventions.h: + (JSC): + * runtime/ArrayPrototype.cpp: + (JSC::arrayProtoFuncSplice): + * runtime/ArrayStorage.h: + (JSC::ArrayStorage::copyHeaderFromDuringGC): + (ArrayStorage): + * runtime/FunctionPrototype.cpp: + (JSC::functionProtoFuncBind): + * runtime/JSArray.cpp: + (JSC::createArrayButterflyInDictionaryIndexingMode): + (JSC::JSArray::setLength): + (JSC::JSArray::pop): + (JSC::JSArray::push): + (JSC::JSArray::sortNumeric): + (JSC::JSArray::sort): + (JSC::JSArray::compactForSorting): + * runtime/JSArray.h: + (JSArray): + (JSC::createArrayButterfly): + (JSC::JSArray::tryCreateUninitialized): + (JSC::constructArray): + * runtime/JSObject.cpp: + (JSC::JSObject::putByIndex): + (JSC::JSObject::createArrayStorage): + (JSC::JSObject::deletePropertyByIndex): + (JSC): + * runtime/JSObject.h: + (JSC::JSObject::initializeIndex): + (JSObject): + +2012-09-20 Mark Lam <mark.lam@apple.com> + + Fixed a missing semicolon in the C++ llint backend. + https://bugs.webkit.org/show_bug.cgi?id=97252. + + Reviewed by Geoff Garen. + + * offlineasm/cloop.rb: + +2012-09-20 Geoffrey Garen <ggaren@apple.com> + + Refactored the interpreter and JIT so they don't dictate closure layout + https://bugs.webkit.org/show_bug.cgi?id=97221 + + Reviewed by Oliver Hunt. + + Capture may change the location of an argument for space efficiency. This + patch removes static assumptions about argument location from the interpreter + and JIT. + + * bytecode/CodeBlock.h: + (JSC::CodeBlock::argumentIndexAfterCapture): + (JSC::ExecState::argumentAfterCapture): Factored out a helper function + so the compiler could share this logic. + + * bytecompiler/NodesCodegen.cpp: + (JSC::BracketAccessorNode::emitBytecode): Don't emit optimized bracket + access on arguments if a parameter has been captured by name. This case is + rare and, where I've seen it in the wild, the optimization mostly failed + anyway due to arguments escape, so I didn't feel like writing and testing + five copies of the code that would handle it in the baseline engines. + + The DFG can still synthesize this optimization even if we don't emit the + optimized bytecode for it. + + * dfg/DFGArgumentsSimplificationPhase.cpp: + (JSC::DFG::ArgumentsSimplificationPhase::run): + * dfg/DFGAssemblyHelpers.h: + (JSC::DFG::AssemblyHelpers::symbolTableFor): + (AssemblyHelpers): Use the right helper function to account for the fact + that a parameter may have been captured by name and moved. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): ASSERT that we haven't inlined + a .apply on captured arguments. Once we do start inlining such things, + we'll need to do a little bit of math here to get them right. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): Added support for bracket access on + an arguments object where arguments have also been captured by name. We + load the true index of the argument from a side vector. Arguments elision + is very powerful in the DFG, so I wanted to keep it working, even in this + rare case. + + * interpreter/Interpreter.cpp: + (JSC::loadVarargs): Use the right helper function to account for the fact + that a parameter may have been captured by name and moved. + + * jit/JITCall.cpp: + (JSC::JIT::compileLoadVarargs): + * jit/JITCall32_64.cpp: + (JSC::JIT::compileLoadVarargs): Don't use the inline copy loop if some + of our arguments have moved, since it would copy stale values. (We still + optimize the actual call, and elide the arguments object.) + 2012-09-20 Gabor Rapcsanyi <rgabor@webkit.org> [Qt] r129045 broke the ARM build diff --git a/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig b/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig index ec35cf673..1b4a75243 100644 --- a/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig +++ b/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig @@ -96,6 +96,7 @@ ENABLE_LEGACY_NOTIFICATIONS_macosx_1070 = ; ENABLE_LEGACY_NOTIFICATIONS_macosx_1080 = ENABLE_LEGACY_NOTIFICATIONS; ENABLE_LEGACY_NOTIFICATIONS_macosx_1090 = ENABLE_LEGACY_NOTIFICATIONS; ENABLE_LEGACY_VENDOR_PREFIXES = ENABLE_LEGACY_VENDOR_PREFIXES; +ENABLE_LEGACY_WEB_AUDIO = ENABLE_LEGACY_WEB_AUDIO; ENABLE_LINK_PREFETCH = ; ENABLE_LINK_PRERENDER = ; ENABLE_MATHML = ENABLE_MATHML; @@ -140,4 +141,4 @@ ENABLE_WIDGET_REGION_macosx = ENABLE_WIDGET_REGION; 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_CSP_NEXT) $(ENABLE_CSS_BOX_DECORATION_BREAK) $(ENABLE_CSS_EXCLUSIONS) $(ENABLE_CSS_FILTERS) $(ENABLE_CSS_HIERARCHIES) $(ENABLE_CSS_IMAGE_ORIENTATION) $(ENABLE_CSS_IMAGE_RESOLUTION) $(ENABLE_CSS_REGIONS) $(ENABLE_CSS_SHADERS) $(ENABLE_CSS_COMPOSITING) $(ENABLE_CSS_STICKY_POSITION) $(ENABLE_CSS_VARIABLES) $(ENABLE_CSS3_TEXT_DECORATION) $(ENABLE_CUSTOM_SCHEME_HANDLER) $(ENABLE_DASHBOARD_SUPPORT) $(ENABLE_DATALIST_ELEMENT) $(ENABLE_DATA_TRANSFER_ITEMS) $(ENABLE_DETAILS_ELEMENT) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DIALOG_ELEMENT) $(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_SPEECH) $(ENABLE_INPUT_TYPE_COLOR) $(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_CSS_VENDOR_PREFIXES) $(ENABLE_LEGACY_NOTIFICATIONS) $(ENABLE_LEGACY_VENDOR_PREFIXES) $(ENABLE_LINK_PREFETCH) $(ENABLE_LINK_PRERENDER) $(ENABLE_MATHML) $(ENABLE_MEDIA_SOURCE) $(ENABLE_MEDIA_STATISTICS) $(ENABLE_METER_ELEMENT) $(ENABLE_MHTML) $(ENABLE_MICRODATA) $(ENABLE_MUTATION_OBSERVERS) $(ENABLE_NAVIGATOR_CONTENT_UTILS) $(ENABLE_NOTIFICATIONS) $(ENABLE_PAGE_VISIBILITY_API) $(ENABLE_PROGRESS_ELEMENT) $(ENABLE_QUOTA) $(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_AUTOSIZING) $(ENABLE_TEXT_NOTIFICATIONS_ONLY) $(ENABLE_TOUCH_ICON_LOADING) $(ENABLE_UNDO_MANAGER) $(ENABLE_VIDEO) $(ENABLE_VIDEO_TRACK) $(ENABLE_WEBGL) $(ENABLE_WEB_AUDIO) $(ENABLE_WEB_SOCKETS) $(ENABLE_WEB_TIMING) $(ENABLE_WIDGET_REGION) $(ENABLE_WORKERS) $(ENABLE_XSLT); +FEATURE_DEFINES = $(ENABLE_3D_RENDERING) $(ENABLE_ACCELERATED_2D_CANVAS) $(ENABLE_ANIMATION_API) $(ENABLE_BLOB) $(ENABLE_CHANNEL_MESSAGING) $(ENABLE_CSP_NEXT) $(ENABLE_CSS_BOX_DECORATION_BREAK) $(ENABLE_CSS_EXCLUSIONS) $(ENABLE_CSS_FILTERS) $(ENABLE_CSS_HIERARCHIES) $(ENABLE_CSS_IMAGE_ORIENTATION) $(ENABLE_CSS_IMAGE_RESOLUTION) $(ENABLE_CSS_REGIONS) $(ENABLE_CSS_SHADERS) $(ENABLE_CSS_COMPOSITING) $(ENABLE_CSS_STICKY_POSITION) $(ENABLE_CSS_VARIABLES) $(ENABLE_CSS3_TEXT_DECORATION) $(ENABLE_CUSTOM_SCHEME_HANDLER) $(ENABLE_DASHBOARD_SUPPORT) $(ENABLE_DATALIST_ELEMENT) $(ENABLE_DATA_TRANSFER_ITEMS) $(ENABLE_DETAILS_ELEMENT) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DIALOG_ELEMENT) $(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_SPEECH) $(ENABLE_INPUT_TYPE_COLOR) $(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_CSS_VENDOR_PREFIXES) $(ENABLE_LEGACY_NOTIFICATIONS) $(ENABLE_LEGACY_VENDOR_PREFIXES) $(ENABLE_LEGACY_WEB_AUDIO) $(ENABLE_LINK_PREFETCH) $(ENABLE_LINK_PRERENDER) $(ENABLE_MATHML) $(ENABLE_MEDIA_SOURCE) $(ENABLE_MEDIA_STATISTICS) $(ENABLE_METER_ELEMENT) $(ENABLE_MHTML) $(ENABLE_MICRODATA) $(ENABLE_MUTATION_OBSERVERS) $(ENABLE_NAVIGATOR_CONTENT_UTILS) $(ENABLE_NOTIFICATIONS) $(ENABLE_PAGE_VISIBILITY_API) $(ENABLE_PROGRESS_ELEMENT) $(ENABLE_QUOTA) $(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_AUTOSIZING) $(ENABLE_TEXT_NOTIFICATIONS_ONLY) $(ENABLE_TOUCH_ICON_LOADING) $(ENABLE_UNDO_MANAGER) $(ENABLE_VIDEO) $(ENABLE_VIDEO_TRACK) $(ENABLE_WEBGL) $(ENABLE_WEB_AUDIO) $(ENABLE_WEB_SOCKETS) $(ENABLE_WEB_TIMING) $(ENABLE_WIDGET_REGION) $(ENABLE_WORKERS) $(ENABLE_XSLT); diff --git a/Source/JavaScriptCore/Configurations/Version.xcconfig b/Source/JavaScriptCore/Configurations/Version.xcconfig index 83578f9e9..ffba40115 100644 --- a/Source/JavaScriptCore/Configurations/Version.xcconfig +++ b/Source/JavaScriptCore/Configurations/Version.xcconfig @@ -22,7 +22,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. MAJOR_VERSION = 537; -MINOR_VERSION = 11; +MINOR_VERSION = 12; TINY_VERSION = 0; FULL_VERSION = $(MAJOR_VERSION).$(MINOR_VERSION); diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def index 4d54364f0..f7c0457bf 100755 --- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def +++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def @@ -135,6 +135,7 @@ EXPORTS ?cryptographicallyRandomValues@WTF@@YAXPAXI@Z ?currentThread@WTF@@YAIXZ ?currentTime@WTF@@YANXZ + ?customHasInstance@JSCell@JSC@@KA_NPAVJSObject@2@PAVExecState@2@VJSValue@2@@Z ?data@CString@WTF@@QBEPBDXZ ?dataLog@WTF@@YAXPBDZZ ?dateToDaysFrom1970@WTF@@YANHHH@Z @@ -222,7 +223,6 @@ EXPORTS ?globalObjectCount@Heap@JSC@@QAEIXZ ?grow@HandleSet@JSC@@AAEXXZ ?growOutOfLineStorage@JSObject@JSC@@QAEPAVButterfly@2@AAVJSGlobalData@2@II@Z - ?hasInstance@JSObject@JSC@@SA_NPAV12@PAVExecState@2@VJSValue@2@2@Z ?hasProperty@JSObject@JSC@@QBE_NPAVExecState@2@I@Z ?hasProperty@JSObject@JSC@@QBE_NPAVExecState@2@VPropertyName@2@@Z ?hashSlowCase@StringImpl@WTF@@ABEIXZ diff --git a/Source/JavaScriptCore/assembler/LinkBuffer.h b/Source/JavaScriptCore/assembler/LinkBuffer.h index 484d3a73f..770144d64 100644 --- a/Source/JavaScriptCore/assembler/LinkBuffer.h +++ b/Source/JavaScriptCore/assembler/LinkBuffer.h @@ -287,6 +287,9 @@ private: #define FINALIZE_CODE(linkBufferReference, dataLogArgumentsForHeading) \ FINALIZE_CODE_IF(Options::showDisassembly(), linkBufferReference, dataLogArgumentsForHeading) +#define FINALIZE_DFG_CODE(linkBufferReference, dataLogArgumentsForHeading) \ + FINALIZE_CODE_IF(Options::showDFGDisassembly(), linkBufferReference, dataLogArgumentsForHeading) + } // namespace JSC #endif // ENABLE(ASSEMBLER) diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h b/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h index 09a88fdda..46d7225d0 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h @@ -743,6 +743,12 @@ public: store8(src, ArmAddress(addressTempRegister, 0)); } + void store8(TrustedImm32 imm, void* address) + { + move(imm, dataTempRegister); + store8(dataTempRegister, address); + } + void store16(RegisterID src, BaseIndex address) { store16(src, setupArmAddress(address)); diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h b/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h index 8b3ce9f03..b3afae8df 100644 --- a/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h +++ b/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h @@ -335,6 +335,13 @@ public: m_assembler.orInsn(dest, dest, dataTempRegister); } + void or32(RegisterID src, AbsoluteAddress dest) + { + load32(dest.m_ptr, dataTempRegister); + m_assembler.orInsn(dataTempRegister, dataTempRegister, src); + store32(dataTempRegister, dest.m_ptr); + } + void rshift32(RegisterID shiftAmount, RegisterID dest) { m_assembler.srav(dest, dest, shiftAmount); diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp index 6b31be221..54dccb9ed 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp @@ -532,8 +532,8 @@ void CodeBlock::dump(ExecState* exec) static_cast<unsigned long>(instructions().size() * sizeof(Instruction)), this, codeTypeToString(codeType()), m_numParameters, m_numCalleeRegisters, m_numVars); - if (m_numCapturedVars) - dataLog("; %d captured var(s)", m_numCapturedVars); + if (m_symbolTable->captureCount()) + dataLog("; %d captured var(s)", m_symbolTable->captureCount()); if (usesArguments()) { dataLog( "; uses arguments, in r%d, r%d", @@ -873,8 +873,11 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& break; } case op_check_has_instance: { - int base = (++it)->u.operand; - dataLog("[%4d] check_has_instance\t\t %s", location, registerName(exec, base).data()); + int r0 = (++it)->u.operand; + int r1 = (++it)->u.operand; + int r2 = (++it)->u.operand; + int offset = (++it)->u.operand; + dataLog("[%4d] check_has_instance\t\t %s, %s, %s, %d(->%d)", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data(), offset, location + offset); dumpBytecodeCommentAndNewLine(location); break; } @@ -882,8 +885,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int r2 = (++it)->u.operand; - int r3 = (++it)->u.operand; - dataLog("[%4d] instanceof\t\t %s, %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data(), registerName(exec, r3).data()); + dataLog("[%4d] instanceof\t\t %s, %s, %s", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data()); dumpBytecodeCommentAndNewLine(location); break; } @@ -1707,7 +1709,6 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other) , m_heap(other.m_heap) , m_numCalleeRegisters(other.m_numCalleeRegisters) , m_numVars(other.m_numVars) - , m_numCapturedVars(other.m_numCapturedVars) , m_isConstructor(other.m_isConstructor) , m_ownerExecutable(*other.m_globalData, other.m_ownerExecutable.get(), other.m_ownerExecutable.get()) , m_globalData(other.m_globalData) @@ -1773,7 +1774,6 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, JSGlo , m_heap(&m_globalObject->globalData().heap) , m_numCalleeRegisters(0) , m_numVars(0) - , m_numCapturedVars(0) , m_isConstructor(isConstructor) , m_numParameters(0) , m_ownerExecutable(globalObject->globalData(), ownerExecutable, ownerExecutable) diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h index d0c969c6d..22c48311c 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.h +++ b/Source/JavaScriptCore/bytecode/CodeBlock.h @@ -432,6 +432,8 @@ namespace JSC { unsigned instructionCount() { return m_instructions.size(); } + int argumentIndexAfterCapture(size_t argument); + #if ENABLE(JIT) void setJITCode(const JITCode& code, MacroAssemblerCodePtr codeWithArityCheck) { @@ -514,7 +516,7 @@ namespace JSC { m_argumentsRegister = argumentsRegister; ASSERT(usesArguments()); } - int argumentsRegister() + int argumentsRegister() const { ASSERT(usesArguments()); return m_argumentsRegister; @@ -529,7 +531,7 @@ namespace JSC { { m_activationRegister = activationRegister; } - int activationRegister() + int activationRegister() const { ASSERT(needsFullScopeChain()); return m_activationRegister; @@ -552,11 +554,24 @@ namespace JSC { if (inlineCallFrame && !operandIsArgument(operand)) return inlineCallFrame->capturedVars.get(operand); - // Our estimate of argument capture is conservative. if (operandIsArgument(operand)) - return needsActivation() || usesArguments(); + return usesArguments(); + + // The activation object isn't in the captured region, but it's "captured" + // in the sense that stores to its location can be observed indirectly. + if (needsActivation() && operand == activationRegister()) + return true; + + // Ditto for the arguments object. + if (usesArguments() && operand == argumentsRegister()) + return true; - return operand < m_numCapturedVars; + // Ditto for the arguments object. + if (usesArguments() && operand == unmodifiedArgumentsRegister(argumentsRegister())) + return true; + + return operand >= m_symbolTable->captureStart() + && operand < m_symbolTable->captureEnd(); } CodeType codeType() const { return m_codeType; } @@ -1174,7 +1189,6 @@ namespace JSC { int m_numCalleeRegisters; int m_numVars; - int m_numCapturedVars; bool m_isConstructor; protected: @@ -1520,6 +1534,18 @@ namespace JSC { return baselineCodeBlock; } + inline int CodeBlock::argumentIndexAfterCapture(size_t argument) + { + if (argument >= static_cast<size_t>(symbolTable()->parameterCount())) + return CallFrame::argumentOffset(argument); + + const SlowArgument* slowArguments = symbolTable()->slowArguments(); + if (!slowArguments || slowArguments[argument].status == SlowArgument::Normal) + return CallFrame::argumentOffset(argument); + + ASSERT(slowArguments[argument].status == SlowArgument::Captured); + return slowArguments[argument].index; + } inline Register& ExecState::r(int index) { @@ -1552,15 +1578,7 @@ namespace JSC { if (!codeBlock()) return this[argumentOffset(argument)].jsValue(); - if (argument >= static_cast<size_t>(codeBlock()->symbolTable()->parameterCount())) - return this[argumentOffset(argument)].jsValue(); - - const SlowArgument* slowArguments = codeBlock()->symbolTable()->slowArguments(); - if (!slowArguments || slowArguments[argument].status == SlowArgument::Normal) - return this[argumentOffset(argument)].jsValue(); - - ASSERT(slowArguments[argument].status == SlowArgument::Captured); - return this[slowArguments[argument].indexIfCaptured].jsValue(); + return this[codeBlock()->argumentIndexAfterCapture(argument)].jsValue(); } #if ENABLE(DFG_JIT) diff --git a/Source/JavaScriptCore/bytecode/Opcode.h b/Source/JavaScriptCore/bytecode/Opcode.h index 87b100056..a5d466154 100644 --- a/Source/JavaScriptCore/bytecode/Opcode.h +++ b/Source/JavaScriptCore/bytecode/Opcode.h @@ -84,8 +84,8 @@ namespace JSC { macro(op_bitxor, 5) \ macro(op_bitor, 5) \ \ - macro(op_check_has_instance, 2) \ - macro(op_instanceof, 5) \ + macro(op_check_has_instance, 5) \ + macro(op_instanceof, 4) \ macro(op_typeof, 3) \ macro(op_is_undefined, 3) \ macro(op_is_boolean, 3) \ diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp index e7a80fe2c..13a2defff 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp @@ -304,8 +304,6 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, JSScope* scope, S // FIXME: Move code that modifies the global object to Interpreter::execute. - codeBlock->m_numCapturedVars = codeBlock->m_numVars; - if (compilationKind == OptimizingCompilation) return; @@ -392,6 +390,8 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, JSScope* sc m_codeBlock->setActivationRegister(m_activationRegister->index()); } + symbolTable->setCaptureStart(m_codeBlock->m_numVars); + if (functionBody->usesArguments() || codeBlock->usesEval() || m_shouldEmitDebugHooks) { // May reify arguments object. RegisterID* unmodifiedArgumentsRegister = addVar(); // Anonymous, so it can't be modified by user code. RegisterID* argumentsRegister = addVar(propertyNames().arguments, false); // Can be changed by assigning to 'arguments'. @@ -423,32 +423,33 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, JSScope* sc } } - bool mayReifyArgumentsObject = codeBlock->usesArguments() || codeBlock->usesEval() || m_shouldEmitDebugHooks; + bool shouldCaptureAllTheThings = m_shouldEmitDebugHooks || codeBlock->usesEval(); + bool capturesAnyArgumentByName = false; - if (functionBody->hasCapturedVariables()) { + Vector<RegisterID*> capturedArguments; + if (functionBody->hasCapturedVariables() || shouldCaptureAllTheThings) { FunctionParameters& parameters = *functionBody->parameters(); + capturedArguments.resize(parameters.size()); for (size_t i = 0; i < parameters.size(); ++i) { - if (!functionBody->captures(parameters[i])) + capturedArguments[i] = 0; + if (!functionBody->captures(parameters[i]) && !shouldCaptureAllTheThings) continue; capturesAnyArgumentByName = true; - break; + capturedArguments[i] = addVar(); } } - if (mayReifyArgumentsObject || capturesAnyArgumentByName) { - symbolTable->setCaptureMode(SharedSymbolTable::AllOfTheThings); - symbolTable->setCaptureStart(-CallFrame::offsetFor(symbolTable->parameterCountIncludingThis())); - } else { - symbolTable->setCaptureMode(SharedSymbolTable::SomeOfTheThings); - symbolTable->setCaptureStart(m_codeBlock->m_numVars); - } - - if (mayReifyArgumentsObject && capturesAnyArgumentByName) { + if (capturesAnyArgumentByName && !codeBlock->isStrictMode()) { size_t parameterCount = symbolTable->parameterCount(); OwnArrayPtr<SlowArgument> slowArguments = adoptArrayPtr(new SlowArgument[parameterCount]); for (size_t i = 0; i < parameterCount; ++i) { + if (!capturedArguments[i]) { + ASSERT(slowArguments[i].status == SlowArgument::Normal); + slowArguments[i].index = CallFrame::argumentOffset(i); + continue; + } slowArguments[i].status = SlowArgument::Captured; - slowArguments[i].indexIfCaptured = CallFrame::argumentOffset(i); + slowArguments[i].index = capturedArguments[i]->index(); } symbolTable->setSlowArguments(slowArguments.release()); } @@ -491,7 +492,7 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, JSScope* sc instructions().append(m_activationRegister->index()); } - codeBlock->m_numCapturedVars = codeBlock->m_numVars; + symbolTable->setCaptureEnd(codeBlock->m_numVars); m_firstLazyFunction = codeBlock->m_numVars; for (size_t i = 0; i < functionStack.size(); ++i) { @@ -518,10 +519,8 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, JSScope* sc addVar(ident, varStack[i].second & DeclarationStacks::IsConstant); } - if (m_shouldEmitDebugHooks || codeBlock->usesEval()) - codeBlock->m_numCapturedVars = codeBlock->m_numVars; - - symbolTable->setCaptureEnd(codeBlock->m_numCapturedVars); + if (shouldCaptureAllTheThings) + symbolTable->setCaptureEnd(codeBlock->m_numVars); FunctionParameters& parameters = *functionBody->parameters(); m_parameters.grow(parameters.size() + 1); // reserve space for "this" @@ -531,9 +530,16 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, JSScope* sc m_thisRegister.setIndex(nextParameterIndex--); m_codeBlock->addParameter(); - for (size_t i = 0; i < parameters.size(); ++i) - addParameter(parameters[i], nextParameterIndex--); - + for (size_t i = 0; i < parameters.size(); ++i, --nextParameterIndex) { + int index = nextParameterIndex; + if (capturedArguments.size() && capturedArguments[i]) { + ASSERT((functionBody->hasCapturedVariables() && functionBody->captures(parameters[i])) || shouldCaptureAllTheThings); + index = capturedArguments[i]->index(); + RegisterID original(nextParameterIndex); + emitMove(capturedArguments[i], &original); + } + addParameter(parameters[i], index); + } preserveLastVar(); // We declare the callee's name last because it should lose to a var, function, and/or parameter declaration. @@ -603,7 +609,6 @@ BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, JSScope* scope, SharedS for (size_t i = 0; i < numVariables; ++i) variables.append(*varStack[i].first); codeBlock->adoptVariables(variables); - codeBlock->m_numCapturedVars = codeBlock->m_numVars; preserveLastVar(); } @@ -1457,18 +1462,21 @@ ResolveResult BytecodeGenerator::resolveConstDecl(const Identifier& property) return ResolveResult::dynamicResolve(scopeDepth()); } -void BytecodeGenerator::emitCheckHasInstance(RegisterID* base) -{ +void BytecodeGenerator::emitCheckHasInstance(RegisterID* dst, RegisterID* value, RegisterID* base, Label* target) +{ + size_t begin = instructions().size(); emitOpcode(op_check_has_instance); + instructions().append(dst->index()); + instructions().append(value->index()); instructions().append(base->index()); + instructions().append(target->bind(begin, instructions().size())); } -RegisterID* BytecodeGenerator::emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* base, RegisterID* basePrototype) +RegisterID* BytecodeGenerator::emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* basePrototype) { emitOpcode(op_instanceof); instructions().append(dst->index()); instructions().append(value->index()); - instructions().append(base->index()); instructions().append(basePrototype->index()); return dst; } diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h index 398719749..1bf1d8f26 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h @@ -455,8 +455,8 @@ namespace JSC { RegisterID* emitPostInc(RegisterID* dst, RegisterID* srcDst); RegisterID* emitPostDec(RegisterID* dst, RegisterID* srcDst); - void emitCheckHasInstance(RegisterID* base); - RegisterID* emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* base, RegisterID* basePrototype); + void emitCheckHasInstance(RegisterID* dst, RegisterID* value, RegisterID* base, Label* target); + RegisterID* emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* basePrototype); RegisterID* emitTypeOf(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_typeof, dst, src); } RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base) { return emitBinaryOp(op_in, dst, property, base, OperandTypes()); } diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp index e4d35471f..823dadf14 100644 --- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp +++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp @@ -320,7 +320,9 @@ RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, Registe RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (m_base->isResolveNode() && generator.willResolveToArguments(static_cast<ResolveNode*>(m_base)->identifier())) { + if (m_base->isResolveNode() + && generator.willResolveToArguments(static_cast<ResolveNode*>(m_base)->identifier()) + && !generator.symbolTable().slowArguments()) { RegisterID* property = generator.emitNode(m_subscript); generator.emitExpressionInfo(divot(), startOffset(), endOffset()); return generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedRegisterForArguments(), property); @@ -1086,15 +1088,20 @@ RegisterID* InstanceOfNode::emitBytecode(BytecodeGenerator& generator, RegisterI { RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); RefPtr<RegisterID> src2 = generator.emitNode(m_expr2); + RefPtr<RegisterID> prototype = generator.newTemporary(); + RefPtr<RegisterID> dstReg = generator.finalDestination(dst, src1.get()); + RefPtr<Label> target = generator.newLabel(); generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - generator.emitCheckHasInstance(src2.get()); + generator.emitCheckHasInstance(dstReg.get(), src1.get(), src2.get(), target.get()); generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - RegisterID* src2Prototype = generator.emitGetById(generator.newTemporary(), src2.get(), generator.globalData()->propertyNames->prototype); + generator.emitGetById(prototype.get(), src2.get(), generator.globalData()->propertyNames->prototype); generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - return generator.emitInstanceOf(generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), src2Prototype); + RegisterID* result = generator.emitInstanceOf(dstReg.get(), src1.get(), prototype.get()); + generator.emitLabel(target.get()); + return result; } // ------------------------------ LogicalOpNode ---------------------------- diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp index 50b9e2b9f..18b5ad02a 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp +++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp @@ -1262,11 +1262,17 @@ bool AbstractState::execute(unsigned indexInBlock) forNode(nodeIndex).set(SpecFunction); break; - case GetScopeChain: + case GetScope: node.setCanExit(false); forNode(nodeIndex).set(SpecCellOther); break; - + + case GetScopeRegisters: + node.setCanExit(false); + forNode(node.child1()).filter(SpecCell); + forNode(nodeIndex).clear(); // The result is not a JS value. + break; + case GetScopedVar: node.setCanExit(false); forNode(nodeIndex).makeTop(); @@ -1477,7 +1483,7 @@ bool AbstractState::execute(unsigned indexInBlock) // Again, sadly, we don't propagate the fact that we've done InstanceOf if (!(m_graph[node.child1()].prediction() & ~SpecCell) && !(forNode(node.child1()).m_type & ~SpecCell)) forNode(node.child1()).filter(SpecCell); - forNode(node.child3()).filter(SpecCell); + forNode(node.child2()).filter(SpecCell); forNode(nodeIndex).set(SpecBoolean); break; diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp index ba6673963..513357424 100644 --- a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp @@ -584,8 +584,8 @@ public: node.convertToGetLocalUnlinked( static_cast<VirtualRegister>( node.codeOrigin.inlineCallFrame->stackOffset + - argumentToOperand(index + 1))); - + m_graph.baselineCodeBlockFor(node.codeOrigin)->argumentIndexAfterCapture(index))); + NodeIndex checkNodeIndex = m_graph.size(); m_graph.append(check); insertionSet.append(indexInBlock, checkNodeIndex); diff --git a/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h b/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h index 57f758c9c..a2003c5bf 100644 --- a/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h +++ b/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h @@ -343,6 +343,25 @@ public: return argumentsRegisterFor(codeOrigin.inlineCallFrame); } + SharedSymbolTable* symbolTableFor(const CodeOrigin& codeOrigin) + { + return baselineCodeBlockFor(codeOrigin)->symbolTable(); + } + + int offsetOfLocals(const CodeOrigin& codeOrigin) + { + if (!codeOrigin.inlineCallFrame) + return 0; + return codeOrigin.inlineCallFrame->stackOffset * sizeof(Register); + } + + int offsetOfArgumentsIncludingThis(const CodeOrigin& codeOrigin) + { + if (!codeOrigin.inlineCallFrame) + return CallFrame::argumentOffsetIncludingThis(0) * sizeof(Register); + return (codeOrigin.inlineCallFrame->stackOffset + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register); + } + Vector<BytecodeAndMachineOffset>& decodedCodeMapFor(CodeBlock*); static const double twoToThe32; diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp index fb897ff5b..901b67b19 100644 --- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp +++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp @@ -467,8 +467,11 @@ private: numArguments = m_inlineStackTop->m_codeBlock->numParameters(); for (unsigned argument = numArguments; argument-- > 1;) flush(argumentToOperand(argument)); - for (unsigned local = m_inlineStackTop->m_codeBlock->m_numCapturedVars; local--;) + for (int local = 0; local < m_inlineStackTop->m_codeBlock->m_numVars; ++local) { + if (!m_inlineStackTop->m_codeBlock->isCaptured(local)) + continue; flush(local); + } } // Get an operand, and perform a ToInt32/ToNumber conversion on it. @@ -2049,14 +2052,13 @@ bool ByteCodeParser::parseBlock(unsigned limit) } case op_check_has_instance: - addToGraph(CheckHasInstance, get(currentInstruction[1].u.operand)); + addToGraph(CheckHasInstance, get(currentInstruction[3].u.operand)); NEXT_OPCODE(op_check_has_instance); case op_instanceof: { NodeIndex value = get(currentInstruction[2].u.operand); - NodeIndex baseValue = get(currentInstruction[3].u.operand); - NodeIndex prototype = get(currentInstruction[4].u.operand); - set(currentInstruction[1].u.operand, addToGraph(InstanceOf, value, baseValue, prototype)); + NodeIndex prototype = get(currentInstruction[3].u.operand); + set(currentInstruction[1].u.operand, addToGraph(InstanceOf, value, prototype)); NEXT_OPCODE(op_instanceof); } @@ -2263,8 +2265,9 @@ bool ByteCodeParser::parseBlock(unsigned limit) int dst = currentInstruction[1].u.operand; int slot = currentInstruction[2].u.operand; int depth = currentInstruction[3].u.operand; - NodeIndex getScopeChain = addToGraph(GetScopeChain, OpInfo(depth)); - NodeIndex getScopedVar = addToGraph(GetScopedVar, OpInfo(slot), OpInfo(prediction), getScopeChain); + NodeIndex getScope = addToGraph(GetScope, OpInfo(depth)); + NodeIndex getScopeRegisters = addToGraph(GetScopeRegisters, getScope); + NodeIndex getScopedVar = addToGraph(GetScopedVar, OpInfo(slot), OpInfo(prediction), getScopeRegisters); set(dst, getScopedVar); NEXT_OPCODE(op_get_scoped_var); } @@ -2272,8 +2275,9 @@ bool ByteCodeParser::parseBlock(unsigned limit) int slot = currentInstruction[1].u.operand; int depth = currentInstruction[2].u.operand; int source = currentInstruction[3].u.operand; - NodeIndex getScopeChain = addToGraph(GetScopeChain, OpInfo(depth)); - addToGraph(PutScopedVar, OpInfo(slot), getScopeChain, get(source)); + NodeIndex getScope = addToGraph(GetScope, OpInfo(depth)); + NodeIndex getScopeRegisters = addToGraph(GetScopeRegisters, getScope); + addToGraph(PutScopedVar, OpInfo(slot), getScope, getScopeRegisters, get(source)); NEXT_OPCODE(op_put_scoped_var); } case op_get_by_id: @@ -2714,6 +2718,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) case op_call_varargs: { ASSERT(m_inlineStackTop->m_inlineCallFrame); ASSERT(currentInstruction[3].u.operand == m_inlineStackTop->m_codeBlock->argumentsRegister()); + ASSERT(!m_inlineStackTop->m_codeBlock->symbolTable()->slowArguments()); // It would be cool to funnel this into handleCall() so that it can handle // inlining. But currently that won't be profitable anyway, since none of the // uses of call_varargs will be inlineable. So we set this up manually and @@ -3282,10 +3287,10 @@ void ByteCodeParser::parseCodeBlock() CodeBlock* codeBlock = m_inlineStackTop->m_codeBlock; #if DFG_ENABLE(DEBUG_VERBOSE) - dataLog("Parsing code block %p. codeType = %s, numCapturedVars = %u, needsFullScopeChain = %s, needsActivation = %s, isStrictMode = %s\n", + dataLog("Parsing code block %p. codeType = %s, captureCount = %u, needsFullScopeChain = %s, needsActivation = %s, isStrictMode = %s\n", codeBlock, codeTypeToString(codeBlock->codeType()), - codeBlock->m_numCapturedVars, + codeBlock->symbolTable()->captureCount(), codeBlock->needsFullScopeChain()?"true":"false", codeBlock->ownerExecutable()->needsActivation()?"true":"false", codeBlock->ownerExecutable()->isStrictMode()?"true":"false"); diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp index 111c15f17..cea2f3c48 100644 --- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp @@ -96,6 +96,9 @@ private: break; Node& otherNode = m_graph[index]; + if (!otherNode.shouldGenerate()) + continue; + if (node.op() != otherNode.op()) continue; @@ -157,38 +160,34 @@ private: return NoNode; } - NodeIndex impureCSE(Node& node) + NodeIndex getArrayLengthElimination(NodeIndex array) { - NodeIndex child1 = canonicalize(node.child1()); - NodeIndex child2 = canonicalize(node.child2()); - NodeIndex child3 = canonicalize(node.child3()); - for (unsigned i = m_indexInBlock; i--;) { NodeIndex index = m_currentBlock->at(i); - if (index == child1 || index == child2 || index == child3) - break; - - Node& otherNode = m_graph[index]; - if (node.op() == otherNode.op() - && node.arithNodeFlags() == otherNode.arithNodeFlags()) { - NodeIndex otherChild = canonicalize(otherNode.child1()); - if (otherChild == NoNode) + Node& node = m_graph[index]; + if (!node.shouldGenerate()) + continue; + switch (node.op()) { + case GetArrayLength: + if (node.child1() == array) return index; - if (otherChild == child1) { - otherChild = canonicalize(otherNode.child2()); - if (otherChild == NoNode) - return index; - if (otherChild == child2) { - otherChild = canonicalize(otherNode.child3()); - if (otherChild == NoNode) - return index; - if (otherChild == child3) - return index; - } + break; + + case PutByVal: + if (!m_graph.byValIsPure(node)) + return NoNode; + switch (node.arrayMode()) { + case ARRAY_STORAGE_TO_HOLE_MODES: + return NoNode; + default: + break; } - } - if (m_graph.clobbersWorld(index)) break; + + default: + if (m_graph.clobbersWorld(index)) + return NoNode; + } } return NoNode; } @@ -216,6 +215,34 @@ private: return NoNode; } + NodeIndex scopedVarLoadElimination(unsigned scopeChainDepth, unsigned varNumber) + { + for (unsigned i = m_indexInBlock; i--;) { + NodeIndex index = m_currentBlock->at(i); + Node& node = m_graph[index]; + switch (node.op()) { + case GetScopedVar: { + Node& getScopeRegisters = m_graph[node.child1()]; + Node& getScope = m_graph[getScopeRegisters.child1()]; + if (getScope.scopeChainDepth() == scopeChainDepth && node.varNumber() == varNumber) + return index; + break; + } + case PutScopedVar: { + Node& getScope = m_graph[node.child1()]; + if (getScope.scopeChainDepth() == scopeChainDepth && node.varNumber() == varNumber) + return node.child3().index(); + break; + } + default: + break; + } + if (m_graph.clobbersWorld(index)) + break; + } + return NoNode; + } + bool globalVarWatchpointElimination(WriteBarrier<Unknown>* registerPointer) { for (unsigned i = m_indexInBlock; i--;) { @@ -267,6 +294,38 @@ private: return NoNode; } + NodeIndex scopedVarStoreElimination(unsigned scopeChainDepth, unsigned varNumber) + { + for (unsigned i = m_indexInBlock; i--;) { + NodeIndex index = m_currentBlock->at(i); + Node& node = m_graph[index]; + if (!node.shouldGenerate()) + continue; + switch (node.op()) { + case PutScopedVar: { + Node& getScope = m_graph[node.child1()]; + if (getScope.scopeChainDepth() == scopeChainDepth && node.varNumber() == varNumber) + return index; + break; + } + + case GetScopedVar: { + Node& getScopeRegisters = m_graph[node.child1()]; + Node& getScope = m_graph[getScopeRegisters.child1()]; + if (getScope.scopeChainDepth() == scopeChainDepth && node.varNumber() == varNumber) + return NoNode; + break; + } + + default: + break; + } + if (m_graph.clobbersWorld(index) || node.canExit()) + return NoNode; + } + return NoNode; + } + NodeIndex getByValLoadElimination(NodeIndex child1, NodeIndex child2) { for (unsigned i = m_indexInBlock; i--;) { @@ -437,7 +496,7 @@ private: break; Node& node = m_graph[index]; if (!node.shouldGenerate()) - break; + continue; switch (node.op()) { case CheckStructure: case ForwardCheckStructure: @@ -690,19 +749,35 @@ private: return NoNode; } - NodeIndex getScopeChainLoadElimination(unsigned depth) + NodeIndex getScopeLoadElimination(unsigned depth) { for (unsigned i = endIndexForPureCSE(); i--;) { NodeIndex index = m_currentBlock->at(i); Node& node = m_graph[index]; if (!node.shouldGenerate()) continue; - if (node.op() == GetScopeChain + if (node.op() == GetScope && node.scopeChainDepth() == depth) return index; } return NoNode; } + + NodeIndex getScopeRegistersLoadElimination(unsigned depth) + { + for (unsigned i = endIndexForPureCSE(); i--;) { + NodeIndex index = m_currentBlock->at(i); + Node& node = m_graph[index]; + if (!node.shouldGenerate()) + continue; + if (node.op() == GetScopeRegisters + && m_graph[node.scope()].scopeChainDepth() == depth) + return index; + } + return NoNode; + } + + NodeIndex getLocalLoadElimination(VirtualRegister local, NodeIndex& relevantLocalOp, bool careAboutClobbering) { @@ -787,7 +862,8 @@ private: return result; } - case GetScopeChain: + case GetScope: + case GetScopeRegisters: if (m_graph.uncheckedActivationRegisterFor(node.codeOrigin) == local) result.mayBeAccessed = true; break; @@ -1078,11 +1154,15 @@ private: break; case GetArrayLength: - setReplacement(impureCSE(node)); + setReplacement(getArrayLengthElimination(node.child1().index())); break; - - case GetScopeChain: - setReplacement(getScopeChainLoadElimination(node.scopeChainDepth())); + + case GetScope: + setReplacement(getScopeLoadElimination(node.scopeChainDepth())); + break; + + case GetScopeRegisters: + setReplacement(getScopeRegistersLoadElimination(m_graph[node.scope()].scopeChainDepth())); break; // Handle nodes that are conditionally pure: these are pure, and can @@ -1106,7 +1186,14 @@ private: case GetGlobalVar: setReplacement(globalVarLoadElimination(node.registerPointer())); break; - + + case GetScopedVar: { + Node& getScopeRegisters = m_graph[node.child1()]; + Node& getScope = m_graph[getScopeRegisters.child1()]; + setReplacement(scopedVarLoadElimination(getScope.scopeChainDepth(), node.varNumber())); + break; + } + case GlobalVarWatchpoint: if (globalVarWatchpointElimination(node.registerPointer())) eliminate(); @@ -1119,6 +1206,14 @@ private: eliminate(globalVarStoreElimination(node.registerPointer())); break; + case PutScopedVar: { + if (m_graph.m_fixpointState == FixpointNotConverged) + break; + Node& getScope = m_graph[node.child1()]; + eliminate(scopedVarStoreElimination(getScope.scopeChainDepth(), node.varNumber())); + break; + } + case GetByVal: if (m_graph.byValIsPure(node)) setReplacement(getByValLoadElimination(node.child1().index(), node.child2().index())); diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h index 64d81f526..b02c9991c 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.h +++ b/Source/JavaScriptCore/dfg/DFGGraph.h @@ -469,6 +469,12 @@ public: return isNumberSpeculation(left) && isNumberSpeculation(right); } + // Note that a 'true' return does not actually mean that the ByVal access clobbers nothing. + // It really means that it will not clobber the entire world. It's still up to you to + // carefully consider things like: + // - PutByVal definitely changes the array it stores to, and may even change its length. + // - PutByOffset definitely changes the object it stores to. + // - and so on. bool byValIsPure(Node& node) { switch (node.arrayMode()) { diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h index 195135c7b..df6191eab 100644 --- a/Source/JavaScriptCore/dfg/DFGNode.h +++ b/Source/JavaScriptCore/dfg/DFGNode.h @@ -466,7 +466,7 @@ struct Node { bool hasScopeChainDepth() { - return op() == GetScopeChain; + return op() == GetScope; } unsigned scopeChainDepth() @@ -475,6 +475,12 @@ struct Node { return m_opInfo; } + Edge scope() + { + ASSERT(op() == GetScopeRegisters); + return child1(); + } + bool hasResult() { return m_flags & NodeResultMask; diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h index 584e28cca..9c93a8ba3 100644 --- a/Source/JavaScriptCore/dfg/DFGNodeType.h +++ b/Source/JavaScriptCore/dfg/DFGNodeType.h @@ -144,10 +144,11 @@ namespace JSC { namespace DFG { macro(GetByOffset, NodeResultJS) \ macro(PutByOffset, NodeMustGenerate) \ macro(GetArrayLength, NodeResultInt32) \ - macro(GetScopeChain, NodeResultJS) \ - macro(GetScopedVar, NodeResultJS | NodeMustGenerate) \ - macro(PutScopedVar, NodeMustGenerate | NodeClobbersWorld) \ - macro(GetGlobalVar, NodeResultJS | NodeMustGenerate) \ + macro(GetScope, NodeResultJS) \ + macro(GetScopeRegisters, NodeResultStorage) \ + macro(GetScopedVar, NodeResultJS) \ + macro(PutScopedVar, NodeMustGenerate) \ + macro(GetGlobalVar, NodeResultJS) \ macro(PutGlobalVar, NodeMustGenerate) \ macro(GlobalVarWatchpoint, NodeMustGenerate) \ macro(PutGlobalVarCheck, NodeMustGenerate) \ diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp index a918bbbe5..d76fd8018 100644 --- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp @@ -447,7 +447,8 @@ private: changed |= setPrediction(SpecInt32); break; } - + + case GetScopeRegisters: case GetButterfly: case GetIndexedPropertyStorage: case AllocatePropertyStorage: @@ -509,7 +510,7 @@ private: break; } - case GetScopeChain: { + case GetScope: { changed |= setPrediction(SpecCellOther); break; } diff --git a/Source/JavaScriptCore/dfg/DFGRepatch.cpp b/Source/JavaScriptCore/dfg/DFGRepatch.cpp index 690f0dd3e..b05537fdf 100644 --- a/Source/JavaScriptCore/dfg/DFGRepatch.cpp +++ b/Source/JavaScriptCore/dfg/DFGRepatch.cpp @@ -216,7 +216,7 @@ static void generateProtoChainAccessStub(ExecState* exec, StructureStubInfo& stu linkRestoreScratch(patchBuffer, needToRestoreScratch, success, fail, failureCases, successLabel, slowCaseLabel); - stubRoutine = FINALIZE_CODE_FOR_STUB( + stubRoutine = FINALIZE_CODE_FOR_DFG_STUB( patchBuffer, ("DFG prototype chain access stub for CodeBlock %p, return point %p", exec->codeBlock(), successLabel.executableAddress())); @@ -277,7 +277,7 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier linkRestoreScratch(patchBuffer, needToRestoreScratch, stubInfo, success, fail, failureCases); - stubInfo.stubRoutine = FINALIZE_CODE_FOR_STUB( + stubInfo.stubRoutine = FINALIZE_CODE_FOR_DFG_STUB( patchBuffer, ("DFG GetById array length stub for CodeBlock %p, return point %p", exec->codeBlock(), stubInfo.callReturnLocation.labelAtOffset( @@ -506,7 +506,7 @@ static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identi RefPtr<JITStubRoutine> stubRoutine = createJITStubRoutine( - FINALIZE_CODE( + FINALIZE_DFG_CODE( patchBuffer, ("DFG GetById polymorphic list access for CodeBlock %p, return point %p", exec->codeBlock(), stubInfo.callReturnLocation.labelAtOffset( @@ -717,7 +717,7 @@ static void emitPutReplaceStub( patchBuffer.link(success, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.dfg.deltaCallToDone)); patchBuffer.link(failure, failureLabel); - stubRoutine = FINALIZE_CODE_FOR_STUB( + stubRoutine = FINALIZE_CODE_FOR_DFG_STUB( patchBuffer, ("DFG PutById replace stub for CodeBlock %p, return point %p", exec->codeBlock(), stubInfo.callReturnLocation.labelAtOffset( @@ -917,9 +917,11 @@ static void emitPutTransitionStub( stubRoutine = createJITStubRoutine( - FINALIZE_CODE( + FINALIZE_DFG_CODE( patchBuffer, - ("DFG PutById transition stub for CodeBlock %p, return point %p", + ("DFG PutById %stransition stub (%p -> %p) for CodeBlock %p, return point %p", + structure->outOfLineCapacity() != oldStructure->outOfLineCapacity() ? "reallocating " : "", + oldStructure, structure, exec->codeBlock(), stubInfo.callReturnLocation.labelAtOffset( stubInfo.patch.dfg.deltaCallToDone).executableAddress())), *globalData, @@ -957,6 +959,11 @@ static bool tryCachePutByID(ExecState* exec, JSValue baseValue, const Identifier && oldStructure->outOfLineCapacity()) return false; + // Skip optimizing the case where we need realloc, and the structure has + // indexing storage. + if (hasIndexingHeader(oldStructure->indexingType())) + return false; + normalizePrototypeChain(exec, baseCell); StructureChain* prototypeChain = structure->prototypeChain(exec); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp index 0228f846a..e42752d8a 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp @@ -2382,7 +2382,7 @@ void SpeculativeJIT::compileInstanceOf(Node& node) // from speculating any more aggressively than we absolutely need to. JSValueOperand value(this, node.child1()); - SpeculateCellOperand prototype(this, node.child3()); + SpeculateCellOperand prototype(this, node.child2()); GPRTemporary scratch(this); GPRReg prototypeReg = prototype.gpr(); @@ -2416,8 +2416,7 @@ void SpeculativeJIT::compileInstanceOf(Node& node) } SpeculateCellOperand value(this, node.child1()); - // Base unused since we speculate default InstanceOf behaviour in CheckHasInstance. - SpeculateCellOperand prototype(this, node.child3()); + SpeculateCellOperand prototype(this, node.child2()); GPRTemporary scratch(this); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp index 22941358a..8039ad2ab 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp @@ -3371,7 +3371,7 @@ void SpeculativeJIT::compile(Node& node) break; } - case GetScopeChain: { + case GetScope: { GPRTemporary result(this); GPRReg resultGPR = result.gpr(); @@ -3392,27 +3392,42 @@ void SpeculativeJIT::compile(Node& node) cellResult(resultGPR, m_compileIndex); break; } - case GetScopedVar: { + case GetScopeRegisters: { SpeculateCellOperand scope(this, node.child1()); + GPRTemporary result(this); + GPRReg scopeGPR = scope.gpr(); + GPRReg resultGPR = result.gpr(); + + m_jit.loadPtr(JITCompiler::Address(scopeGPR, JSVariableObject::offsetOfRegisters()), resultGPR); + storageResult(resultGPR, m_compileIndex); + break; + } + case GetScopedVar: { + StorageOperand registers(this, node.child1()); GPRTemporary resultTag(this); GPRTemporary resultPayload(this); + GPRReg registersGPR = registers.gpr(); GPRReg resultTagGPR = resultTag.gpr(); GPRReg resultPayloadGPR = resultPayload.gpr(); - m_jit.loadPtr(JITCompiler::Address(scope.gpr(), JSVariableObject::offsetOfRegisters()), resultPayloadGPR); - m_jit.load32(JITCompiler::Address(resultPayloadGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR); - m_jit.load32(JITCompiler::Address(resultPayloadGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR); + m_jit.load32(JITCompiler::Address(registersGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR); + m_jit.load32(JITCompiler::Address(registersGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR); jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex); break; } case PutScopedVar: { SpeculateCellOperand scope(this, node.child1()); + StorageOperand registers(this, node.child2()); + JSValueOperand value(this, node.child3()); GPRTemporary scratchRegister(this); + GPRReg scopeGPR = scope.gpr(); + GPRReg registersGPR = registers.gpr(); + GPRReg valueTagGPR = value.tagGPR(); + GPRReg valuePayloadGPR = value.payloadGPR(); GPRReg scratchGPR = scratchRegister.gpr(); - m_jit.loadPtr(JITCompiler::Address(scope.gpr(), JSVariableObject::offsetOfRegisters()), scratchGPR); - JSValueOperand value(this, node.child2()); - m_jit.store32(value.tagGPR(), JITCompiler::Address(scratchGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag))); - m_jit.store32(value.payloadGPR(), JITCompiler::Address(scratchGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload))); - writeBarrier(scope.gpr(), value.tagGPR(), node.child2(), WriteBarrierForVariableAccess, scratchGPR); + + m_jit.store32(valueTagGPR, JITCompiler::Address(registersGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag))); + m_jit.store32(valuePayloadGPR, JITCompiler::Address(registersGPR, node.varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload))); + writeBarrier(scopeGPR, valueTagGPR, node.child2(), WriteBarrierForVariableAccess, scratchGPR); noResult(m_compileIndex); break; } @@ -4202,23 +4217,50 @@ void SpeculativeJIT::compile(Node& node) JITCompiler::payloadFor(RegisterFile::ArgumentCount))); } + JITCompiler::JumpList slowArgument; + JITCompiler::JumpList slowArgumentOutOfBounds; + if (const SlowArgument* slowArguments = m_jit.symbolTableFor(node.codeOrigin)->slowArguments()) { + slowArgumentOutOfBounds.append( + m_jit.branch32( + JITCompiler::AboveOrEqual, indexGPR, + Imm32(m_jit.symbolTableFor(node.codeOrigin)->parameterCount()))); + + COMPILE_ASSERT(sizeof(SlowArgument) == 8, SlowArgument_size_is_eight_bytes); + m_jit.move(ImmPtr(slowArguments), resultPayloadGPR); + m_jit.load32( + JITCompiler::BaseIndex( + resultPayloadGPR, indexGPR, JITCompiler::TimesEight, + OBJECT_OFFSETOF(SlowArgument, index)), + resultPayloadGPR); + + m_jit.load32( + JITCompiler::BaseIndex( + GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight, + m_jit.offsetOfLocals(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), + resultTagGPR); + m_jit.load32( + JITCompiler::BaseIndex( + GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight, + m_jit.offsetOfLocals(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), + resultPayloadGPR); + slowArgument.append(m_jit.jump()); + } + slowArgumentOutOfBounds.link(&m_jit); + m_jit.neg32(resultPayloadGPR); - size_t baseOffset = - ((node.codeOrigin.inlineCallFrame - ? node.codeOrigin.inlineCallFrame->stackOffset - : 0) + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register); m_jit.load32( JITCompiler::BaseIndex( GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight, - baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), + m_jit.offsetOfArgumentsIncludingThis(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR); m_jit.load32( JITCompiler::BaseIndex( GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight, - baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), + m_jit.offsetOfArgumentsIncludingThis(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR); + slowArgument.link(&m_jit); jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex); break; } @@ -4252,21 +4294,46 @@ void SpeculativeJIT::compile(Node& node) JITCompiler::payloadFor(RegisterFile::ArgumentCount))); } + JITCompiler::JumpList slowArgument; + JITCompiler::JumpList slowArgumentOutOfBounds; + if (const SlowArgument* slowArguments = m_jit.symbolTableFor(node.codeOrigin)->slowArguments()) { + slowArgumentOutOfBounds.append( + m_jit.branch32( + JITCompiler::AboveOrEqual, indexGPR, + Imm32(m_jit.symbolTableFor(node.codeOrigin)->parameterCount()))); + + COMPILE_ASSERT(sizeof(SlowArgument) == 8, SlowArgument_size_is_eight_bytes); + m_jit.move(ImmPtr(slowArguments), resultPayloadGPR); + m_jit.load32( + JITCompiler::BaseIndex( + resultPayloadGPR, indexGPR, JITCompiler::TimesEight, + OBJECT_OFFSETOF(SlowArgument, index)), + resultPayloadGPR); + m_jit.load32( + JITCompiler::BaseIndex( + GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight, + m_jit.offsetOfLocals(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), + resultTagGPR); + m_jit.load32( + JITCompiler::BaseIndex( + GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight, + m_jit.offsetOfLocals(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), + resultPayloadGPR); + slowArgument.append(m_jit.jump()); + } + slowArgumentOutOfBounds.link(&m_jit); + m_jit.neg32(resultPayloadGPR); - size_t baseOffset = - ((node.codeOrigin.inlineCallFrame - ? node.codeOrigin.inlineCallFrame->stackOffset - : 0) + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register); m_jit.load32( JITCompiler::BaseIndex( GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight, - baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), + m_jit.offsetOfArgumentsIncludingThis(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR); m_jit.load32( JITCompiler::BaseIndex( GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight, - baseOffset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), + m_jit.offsetOfArgumentsIncludingThis(node.codeOrigin) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR); if (node.codeOrigin.inlineCallFrame) { @@ -4284,6 +4351,7 @@ void SpeculativeJIT::compile(Node& node) m_jit.argumentsRegisterFor(node.codeOrigin), indexGPR)); } + slowArgument.link(&m_jit); jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex); break; } diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp index 87be658ad..8488d261d 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp @@ -3380,7 +3380,7 @@ void SpeculativeJIT::compile(Node& node) break; } - case GetScopeChain: { + case GetScope: { GPRTemporary result(this); GPRReg resultGPR = result.gpr(); @@ -3401,23 +3401,39 @@ void SpeculativeJIT::compile(Node& node) cellResult(resultGPR, m_compileIndex); break; } - case GetScopedVar: { + case GetScopeRegisters: { SpeculateCellOperand scope(this, node.child1()); GPRTemporary result(this); + GPRReg scopeGPR = scope.gpr(); + GPRReg resultGPR = result.gpr(); + + m_jit.loadPtr(JITCompiler::Address(scopeGPR, JSVariableObject::offsetOfRegisters()), resultGPR); + storageResult(resultGPR, m_compileIndex); + break; + } + case GetScopedVar: { + StorageOperand registers(this, node.child1()); + GPRTemporary result(this); + GPRReg registersGPR = registers.gpr(); GPRReg resultGPR = result.gpr(); - m_jit.loadPtr(JITCompiler::Address(scope.gpr(), JSVariableObject::offsetOfRegisters()), resultGPR); - m_jit.loadPtr(JITCompiler::Address(resultGPR, node.varNumber() * sizeof(Register)), resultGPR); + + m_jit.loadPtr(JITCompiler::Address(registersGPR, node.varNumber() * sizeof(Register)), resultGPR); jsValueResult(resultGPR, m_compileIndex); break; } case PutScopedVar: { SpeculateCellOperand scope(this, node.child1()); + StorageOperand registers(this, node.child2()); + JSValueOperand value(this, node.child3()); GPRTemporary scratchRegister(this); + + GPRReg scopeGPR = scope.gpr(); + GPRReg registersGPR = registers.gpr(); + GPRReg valueGPR = value.gpr(); GPRReg scratchGPR = scratchRegister.gpr(); - m_jit.loadPtr(JITCompiler::Address(scope.gpr(), JSVariableObject::offsetOfRegisters()), scratchGPR); - JSValueOperand value(this, node.child2()); - m_jit.storePtr(value.gpr(), JITCompiler::Address(scratchGPR, node.varNumber() * sizeof(Register))); - writeBarrier(scope.gpr(), value.gpr(), node.child2(), WriteBarrierForVariableAccess, scratchGPR); + + m_jit.storePtr(valueGPR, JITCompiler::Address(registersGPR, node.varNumber() * sizeof(Register))); + writeBarrier(scopeGPR, valueGPR, node.child3(), WriteBarrierForVariableAccess, scratchGPR); noResult(m_compileIndex); break; } @@ -4122,7 +4138,7 @@ void SpeculativeJIT::compile(Node& node) GPRTemporary result(this); GPRReg indexGPR = index.gpr(); GPRReg resultGPR = result.gpr(); - + if (!isEmptySpeculation( m_state.variables().operand( m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) { @@ -4150,18 +4166,40 @@ void SpeculativeJIT::compile(Node& node) resultGPR, JITCompiler::payloadFor(RegisterFile::ArgumentCount))); } - + + JITCompiler::JumpList slowArgument; + JITCompiler::JumpList slowArgumentOutOfBounds; + if (const SlowArgument* slowArguments = m_jit.symbolTableFor(node.codeOrigin)->slowArguments()) { + slowArgumentOutOfBounds.append( + m_jit.branch32( + JITCompiler::AboveOrEqual, indexGPR, + Imm32(m_jit.symbolTableFor(node.codeOrigin)->parameterCount()))); + + COMPILE_ASSERT(sizeof(SlowArgument) == 8, SlowArgument_size_is_eight_bytes); + m_jit.move(ImmPtr(slowArguments), resultGPR); + m_jit.load32( + JITCompiler::BaseIndex( + resultGPR, indexGPR, JITCompiler::TimesEight, + OBJECT_OFFSETOF(SlowArgument, index)), + resultGPR); + m_jit.signExtend32ToPtr(resultGPR, resultGPR); + m_jit.loadPtr( + JITCompiler::BaseIndex( + GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight, m_jit.offsetOfLocals(node.codeOrigin)), + resultGPR); + slowArgument.append(m_jit.jump()); + } + slowArgumentOutOfBounds.link(&m_jit); + m_jit.neg32(resultGPR); m_jit.signExtend32ToPtr(resultGPR, resultGPR); m_jit.loadPtr( JITCompiler::BaseIndex( - GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight, - ((node.codeOrigin.inlineCallFrame - ? node.codeOrigin.inlineCallFrame->stackOffset - : 0) + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register)), + GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight, m_jit.offsetOfArgumentsIncludingThis(node.codeOrigin)), resultGPR); + slowArgument.link(&m_jit); jsValueResult(resultGPR, m_compileIndex); break; } @@ -4194,15 +4232,36 @@ void SpeculativeJIT::compile(Node& node) JITCompiler::payloadFor(RegisterFile::ArgumentCount))); } + JITCompiler::JumpList slowArgument; + JITCompiler::JumpList slowArgumentOutOfBounds; + if (const SlowArgument* slowArguments = m_jit.symbolTableFor(node.codeOrigin)->slowArguments()) { + slowArgumentOutOfBounds.append( + m_jit.branch32( + JITCompiler::AboveOrEqual, indexGPR, + Imm32(m_jit.symbolTableFor(node.codeOrigin)->parameterCount()))); + + COMPILE_ASSERT(sizeof(SlowArgument) == 8, SlowArgument_size_is_eight_bytes); + m_jit.move(ImmPtr(slowArguments), resultGPR); + m_jit.load32( + JITCompiler::BaseIndex( + resultGPR, indexGPR, JITCompiler::TimesEight, + OBJECT_OFFSETOF(SlowArgument, index)), + resultGPR); + m_jit.signExtend32ToPtr(resultGPR, resultGPR); + m_jit.loadPtr( + JITCompiler::BaseIndex( + GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight, m_jit.offsetOfLocals(node.codeOrigin)), + resultGPR); + slowArgument.append(m_jit.jump()); + } + slowArgumentOutOfBounds.link(&m_jit); + m_jit.neg32(resultGPR); m_jit.signExtend32ToPtr(resultGPR, resultGPR); m_jit.loadPtr( JITCompiler::BaseIndex( - GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight, - ((node.codeOrigin.inlineCallFrame - ? node.codeOrigin.inlineCallFrame->stackOffset - : 0) + CallFrame::argumentOffsetIncludingThis(0)) * sizeof(Register)), + GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight, m_jit.offsetOfArgumentsIncludingThis(node.codeOrigin)), resultGPR); if (node.codeOrigin.inlineCallFrame) { @@ -4220,6 +4279,7 @@ void SpeculativeJIT::compile(Node& node) indexGPR)); } + slowArgument.link(&m_jit); jsValueResult(resultGPR, m_compileIndex); break; } diff --git a/Source/JavaScriptCore/heap/MachineStackMarker.cpp b/Source/JavaScriptCore/heap/MachineStackMarker.cpp index 26453c4f3..613edd08c 100644 --- a/Source/JavaScriptCore/heap/MachineStackMarker.cpp +++ b/Source/JavaScriptCore/heap/MachineStackMarker.cpp @@ -96,7 +96,7 @@ typedef pthread_t PlatformThread; static const int SigThreadSuspendResume = SIGUSR2; #if defined(SA_RESTART) -static void pthreadSignalHandlerSuspendResume(int signo) +static void pthreadSignalHandlerSuspendResume(int) { sigset_t signalSet; sigemptyset(&signalSet); diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp index ef6cbd5a6..3b3409bd6 100644 --- a/Source/JavaScriptCore/interpreter/Interpreter.cpp +++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp @@ -131,14 +131,6 @@ static NEVER_INLINE bool isInvalidParamForIn(CallFrame* callFrame, JSValue value exceptionData = createInvalidParamError(callFrame, "in" , value); return true; } - -static NEVER_INLINE bool isInvalidParamForInstanceOf(CallFrame* callFrame, JSValue value, JSValue& exceptionData) -{ - if (value.isObject() && asObject(value)->structure()->typeInfo().implementsHasInstance()) - return false; - exceptionData = createInvalidParamError(callFrame, "instanceof" , value); - return true; -} #endif JSValue eval(CallFrame* callFrame) @@ -202,7 +194,7 @@ CallFrame* loadVarargs(CallFrame* callFrame, RegisterFile* registerFile, JSValue newCallFrame->setArgumentCountIncludingThis(argumentCountIncludingThis); newCallFrame->setThisValue(thisValue); for (size_t i = 0; i < callFrame->argumentCount(); ++i) - newCallFrame->setArgument(i, callFrame->argument(i)); + newCallFrame->setArgument(i, callFrame->argumentAfterCapture(i)); return newCallFrame; } @@ -2401,14 +2393,32 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi JSC API*). Raises an exception if register constructor is not an valid parameter for instanceof. */ - int base = vPC[1].u.operand; + int dst = vPC[1].u.operand; + int value = vPC[2].u.operand; + int base = vPC[3].u.operand; + int target = vPC[4].u.operand; + JSValue baseVal = callFrame->r(base).jsValue(); - if (isInvalidParamForInstanceOf(callFrame, baseVal, exceptionValue)) - goto vm_throw; + if (baseVal.isObject()) { + TypeInfo info = asObject(baseVal)->structure()->typeInfo(); + if (info.implementsDefaultHasInstance()) { + vPC += OPCODE_LENGTH(op_check_has_instance); + NEXT_INSTRUCTION(); + } + if (info.implementsHasInstance()) { + JSValue baseVal = callFrame->r(base).jsValue(); + bool result = asObject(baseVal)->methodTable()->customHasInstance(asObject(baseVal), callFrame, callFrame->r(value).jsValue()); + CHECK_FOR_EXCEPTION(); + callFrame->uncheckedR(dst) = jsBoolean(result); - vPC += OPCODE_LENGTH(op_check_has_instance); - NEXT_INSTRUCTION(); + vPC += target; + NEXT_INSTRUCTION(); + } + } + + exceptionValue = createInvalidParamError(callFrame, "instanceof" , baseVal); + goto vm_throw; } DEFINE_OPCODE(op_instanceof) { /* instanceof dst(r) value(r) constructor(r) constructorProto(r) @@ -2425,14 +2435,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi */ int dst = vPC[1].u.operand; int value = vPC[2].u.operand; - int base = vPC[3].u.operand; - int baseProto = vPC[4].u.operand; - - JSValue baseVal = callFrame->r(base).jsValue(); - - ASSERT(!isInvalidParamForInstanceOf(callFrame, baseVal, exceptionValue)); + int baseProto = vPC[3].u.operand; - bool result = asObject(baseVal)->methodTable()->hasInstance(asObject(baseVal), callFrame, callFrame->r(value).jsValue(), callFrame->r(baseProto).jsValue()); + bool result = JSObject::defaultHasInstance(callFrame, callFrame->r(value).jsValue(), callFrame->r(baseProto).jsValue()); CHECK_FOR_EXCEPTION(); callFrame->uncheckedR(dst) = jsBoolean(result); diff --git a/Source/JavaScriptCore/jit/JITCall.cpp b/Source/JavaScriptCore/jit/JITCall.cpp index f6ea71e17..b5f4f8278 100644 --- a/Source/JavaScriptCore/jit/JITCall.cpp +++ b/Source/JavaScriptCore/jit/JITCall.cpp @@ -66,7 +66,11 @@ void JIT::compileLoadVarargs(Instruction* instruction) JumpList slowCase; JumpList end; - if (m_codeBlock->usesArguments() && arguments == m_codeBlock->argumentsRegister()) { + bool canOptimize = m_codeBlock->usesArguments() + && arguments == m_codeBlock->argumentsRegister() + && !m_codeBlock->symbolTable()->slowArguments(); + + if (canOptimize) { emitGetVirtualRegister(arguments, regT0); slowCase.append(branchPtr(NotEqual, regT0, TrustedImmPtr(JSValue::encode(JSValue())))); @@ -103,7 +107,7 @@ void JIT::compileLoadVarargs(Instruction* instruction) end.append(jump()); } - if (m_codeBlock->usesArguments() && arguments == m_codeBlock->argumentsRegister()) + if (canOptimize) slowCase.link(this); JITStubCall stubCall(this, cti_op_load_varargs); @@ -112,7 +116,7 @@ void JIT::compileLoadVarargs(Instruction* instruction) stubCall.addArgument(Imm32(firstFreeRegister)); stubCall.call(regT1); - if (m_codeBlock->usesArguments() && arguments == m_codeBlock->argumentsRegister()) + if (canOptimize) end.link(this); } diff --git a/Source/JavaScriptCore/jit/JITCall32_64.cpp b/Source/JavaScriptCore/jit/JITCall32_64.cpp index 6195d0bb9..09727d532 100644 --- a/Source/JavaScriptCore/jit/JITCall32_64.cpp +++ b/Source/JavaScriptCore/jit/JITCall32_64.cpp @@ -141,7 +141,11 @@ void JIT::compileLoadVarargs(Instruction* instruction) JumpList slowCase; JumpList end; - if (m_codeBlock->usesArguments() && arguments == m_codeBlock->argumentsRegister()) { + bool canOptimize = m_codeBlock->usesArguments() + && arguments == m_codeBlock->argumentsRegister() + && !m_codeBlock->symbolTable()->slowArguments(); + + if (canOptimize) { emitLoadTag(arguments, regT1); slowCase.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::EmptyValueTag))); @@ -180,7 +184,7 @@ void JIT::compileLoadVarargs(Instruction* instruction) end.append(jump()); } - if (m_codeBlock->usesArguments() && arguments == m_codeBlock->argumentsRegister()) + if (canOptimize) slowCase.link(this); JITStubCall stubCall(this, cti_op_load_varargs); @@ -189,7 +193,7 @@ void JIT::compileLoadVarargs(Instruction* instruction) stubCall.addArgument(Imm32(firstFreeRegister)); stubCall.call(regT3); - if (m_codeBlock->usesArguments() && arguments == m_codeBlock->argumentsRegister()) + if (canOptimize) end.link(this); } diff --git a/Source/JavaScriptCore/jit/JITInlineMethods.h b/Source/JavaScriptCore/jit/JITInlineMethods.h index a4f9107df..ed63ad348 100644 --- a/Source/JavaScriptCore/jit/JITInlineMethods.h +++ b/Source/JavaScriptCore/jit/JITInlineMethods.h @@ -552,6 +552,7 @@ inline void JIT::emitArrayProfilingSiteForBytecodeIndex(RegisterID structureAndI #if ENABLE(VALUE_PROFILER) emitArrayProfilingSite(structureAndIndexingType, scratch, m_codeBlock->getOrAddArrayProfile(bytecodeIndex)); #else + UNUSED_PARAM(bytecodeIndex); emitArrayProfilingSite(structureAndIndexingType, scratch, 0); #endif } diff --git a/Source/JavaScriptCore/jit/JITOpcodes.cpp b/Source/JavaScriptCore/jit/JITOpcodes.cpp index 642aabb2a..3b7f38dc7 100644 --- a/Source/JavaScriptCore/jit/JITOpcodes.cpp +++ b/Source/JavaScriptCore/jit/JITOpcodes.cpp @@ -407,7 +407,7 @@ void JIT::emitSlow_op_new_object(Instruction* currentInstruction, Vector<SlowCas void JIT::emit_op_check_has_instance(Instruction* currentInstruction) { - unsigned baseVal = currentInstruction[1].u.operand; + unsigned baseVal = currentInstruction[3].u.operand; emitGetVirtualRegister(baseVal, regT0); @@ -416,20 +416,18 @@ void JIT::emit_op_check_has_instance(Instruction* currentInstruction) // Check that baseVal 'ImplementsHasInstance'. loadPtr(Address(regT0, JSCell::structureOffset()), regT0); - addSlowCase(branchTest8(Zero, Address(regT0, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsHasInstance))); + addSlowCase(branchTest8(Zero, Address(regT0, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsDefaultHasInstance))); } void JIT::emit_op_instanceof(Instruction* currentInstruction) { unsigned dst = currentInstruction[1].u.operand; unsigned value = currentInstruction[2].u.operand; - unsigned baseVal = currentInstruction[3].u.operand; - unsigned proto = currentInstruction[4].u.operand; + unsigned proto = currentInstruction[3].u.operand; // Load the operands (baseVal, proto, and value respectively) into registers. // We use regT0 for baseVal since we will be done with this first, and we can then use it for the result. emitGetVirtualRegister(value, regT2); - emitGetVirtualRegister(baseVal, regT0); emitGetVirtualRegister(proto, regT1); // Check that proto are cells. baseVal must be a cell - this is checked by op_check_has_instance. @@ -440,11 +438,6 @@ void JIT::emit_op_instanceof(Instruction* currentInstruction) loadPtr(Address(regT1, JSCell::structureOffset()), regT3); addSlowCase(emitJumpIfNotObject(regT3)); - // Fixme: this check is only needed because the JSC API allows HasInstance to be overridden; we should deprecate this. - // Check that baseVal 'ImplementsDefaultHasInstance'. - loadPtr(Address(regT0, JSCell::structureOffset()), regT0); - addSlowCase(branchTest8(Zero, Address(regT0, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsDefaultHasInstance))); - // Optimistically load the result true, and start looping. // Initially, regT1 still contains proto and regT2 still contains value. // As we loop regT2 will be updated with its prototype, recursively walking the prototype chain. @@ -1452,29 +1445,31 @@ void JIT::emitSlow_op_nstricteq(Instruction* currentInstruction, Vector<SlowCase void JIT::emitSlow_op_check_has_instance(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { - unsigned baseVal = currentInstruction[1].u.operand; + unsigned dst = currentInstruction[1].u.operand; + unsigned value = currentInstruction[2].u.operand; + unsigned baseVal = currentInstruction[3].u.operand; linkSlowCaseIfNotJSCell(iter, baseVal); linkSlowCase(iter); JITStubCall stubCall(this, cti_op_check_has_instance); + stubCall.addArgument(value, regT2); stubCall.addArgument(baseVal, regT2); - stubCall.call(); + stubCall.call(dst); + + emitJumpSlowToHot(jump(), currentInstruction[4].u.operand); } void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { unsigned dst = currentInstruction[1].u.operand; unsigned value = currentInstruction[2].u.operand; - unsigned baseVal = currentInstruction[3].u.operand; - unsigned proto = currentInstruction[4].u.operand; + unsigned proto = currentInstruction[3].u.operand; linkSlowCaseIfNotJSCell(iter, value); linkSlowCaseIfNotJSCell(iter, proto); linkSlowCase(iter); - linkSlowCase(iter); JITStubCall stubCall(this, cti_op_instanceof); stubCall.addArgument(value, regT2); - stubCall.addArgument(baseVal, regT2); stubCall.addArgument(proto, regT2); stubCall.call(dst); } diff --git a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp index adfb57341..21744fba8 100644 --- a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp +++ b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp @@ -543,7 +543,7 @@ void JIT::emitSlow_op_new_object(Instruction* currentInstruction, Vector<SlowCas void JIT::emit_op_check_has_instance(Instruction* currentInstruction) { - unsigned baseVal = currentInstruction[1].u.operand; + unsigned baseVal = currentInstruction[3].u.operand; emitLoadPayload(baseVal, regT0); @@ -552,20 +552,18 @@ void JIT::emit_op_check_has_instance(Instruction* currentInstruction) // Check that baseVal 'ImplementsHasInstance'. loadPtr(Address(regT0, JSCell::structureOffset()), regT0); - addSlowCase(branchTest8(Zero, Address(regT0, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsHasInstance))); + addSlowCase(branchTest8(Zero, Address(regT0, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsDefaultHasInstance))); } void JIT::emit_op_instanceof(Instruction* currentInstruction) { unsigned dst = currentInstruction[1].u.operand; unsigned value = currentInstruction[2].u.operand; - unsigned baseVal = currentInstruction[3].u.operand; - unsigned proto = currentInstruction[4].u.operand; + unsigned proto = currentInstruction[3].u.operand; // Load the operands into registers. // We use regT0 for baseVal since we will be done with this first, and we can then use it for the result. emitLoadPayload(value, regT2); - emitLoadPayload(baseVal, regT0); emitLoadPayload(proto, regT1); // Check that proto are cells. baseVal must be a cell - this is checked by op_check_has_instance. @@ -576,11 +574,6 @@ void JIT::emit_op_instanceof(Instruction* currentInstruction) loadPtr(Address(regT1, JSCell::structureOffset()), regT3); addSlowCase(emitJumpIfNotObject(regT3)); - // Fixme: this check is only needed because the JSC API allows HasInstance to be overridden; we should deprecate this. - // Check that baseVal 'ImplementsDefaultHasInstance'. - loadPtr(Address(regT0, JSCell::structureOffset()), regT0); - addSlowCase(branchTest8(Zero, Address(regT0, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsDefaultHasInstance))); - // Optimistically load the result true, and start looping. // Initially, regT1 still contains proto and regT2 still contains value. // As we loop regT2 will be updated with its prototype, recursively walking the prototype chain. @@ -604,31 +597,33 @@ void JIT::emit_op_instanceof(Instruction* currentInstruction) void JIT::emitSlow_op_check_has_instance(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { - unsigned baseVal = currentInstruction[1].u.operand; + unsigned dst = currentInstruction[1].u.operand; + unsigned value = currentInstruction[2].u.operand; + unsigned baseVal = currentInstruction[3].u.operand; linkSlowCaseIfNotJSCell(iter, baseVal); linkSlowCase(iter); JITStubCall stubCall(this, cti_op_check_has_instance); + stubCall.addArgument(value); stubCall.addArgument(baseVal); - stubCall.call(); + stubCall.call(dst); + + emitJumpSlowToHot(jump(), currentInstruction[4].u.operand); } void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { unsigned dst = currentInstruction[1].u.operand; unsigned value = currentInstruction[2].u.operand; - unsigned baseVal = currentInstruction[3].u.operand; - unsigned proto = currentInstruction[4].u.operand; + unsigned proto = currentInstruction[3].u.operand; linkSlowCaseIfNotJSCell(iter, value); linkSlowCaseIfNotJSCell(iter, proto); linkSlowCase(iter); - linkSlowCase(iter); JITStubCall stubCall(this, cti_op_instanceof); stubCall.addArgument(value); - stubCall.addArgument(baseVal); stubCall.addArgument(proto); stubCall.call(dst); } diff --git a/Source/JavaScriptCore/jit/JITStubRoutine.h b/Source/JavaScriptCore/jit/JITStubRoutine.h index 4400589ff..a46fcfd1a 100644 --- a/Source/JavaScriptCore/jit/JITStubRoutine.h +++ b/Source/JavaScriptCore/jit/JITStubRoutine.h @@ -153,6 +153,9 @@ protected: #define FINALIZE_CODE_FOR_STUB(patchBuffer, dataLogArguments) \ (adoptRef(new JITStubRoutine(FINALIZE_CODE((patchBuffer), dataLogArguments)))) +#define FINALIZE_CODE_FOR_DFG_STUB(patchBuffer, dataLogArguments) \ + (adoptRef(new JITStubRoutine(FINALIZE_DFG_CODE((patchBuffer), dataLogArguments)))) + } // namespace JSC #endif // ENABLE(JIT) diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp index e63f06cef..da507838a 100644 --- a/Source/JavaScriptCore/jit/JITStubs.cpp +++ b/Source/JavaScriptCore/jit/JITStubs.cpp @@ -1937,21 +1937,27 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_string_fail) return JSValue::encode(result); } -DEFINE_STUB_FUNCTION(void, op_check_has_instance) +DEFINE_STUB_FUNCTION(EncodedJSValue, op_check_has_instance) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; - JSValue baseVal = stackFrame.args[0].jsValue(); + JSValue value = stackFrame.args[0].jsValue(); + JSValue baseVal = stackFrame.args[1].jsValue(); + + if (baseVal.isObject()) { + JSObject* baseObject = asObject(baseVal); + ASSERT(!baseObject->structure()->typeInfo().implementsDefaultHasInstance()); + if (baseObject->structure()->typeInfo().implementsHasInstance()) { + bool result = baseObject->methodTable()->customHasInstance(baseObject, callFrame, value); + CHECK_FOR_EXCEPTION_AT_END(); + return JSValue::encode(jsBoolean(result)); + } + } - // ECMA-262 15.3.5.3: - // Throw an exception either if baseVal is not an object, or if it does not implement 'HasInstance' (i.e. is a function). -#ifndef NDEBUG - TypeInfo typeInfo(UnspecifiedType); - ASSERT(!baseVal.isObject() || !(typeInfo = asObject(baseVal)->structure()->typeInfo()).implementsHasInstance()); -#endif stackFrame.globalData->exception = createInvalidParamError(callFrame, "instanceof", baseVal); VM_THROW_EXCEPTION_AT_END(); + return JSValue::encode(JSValue()); } #if ENABLE(DFG_JIT) @@ -2082,10 +2088,11 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_instanceof) CallFrame* callFrame = stackFrame.callFrame; JSValue value = stackFrame.args[0].jsValue(); - JSValue baseVal = stackFrame.args[1].jsValue(); - JSValue proto = stackFrame.args[2].jsValue(); + JSValue proto = stackFrame.args[1].jsValue(); - bool result = CommonSlowPaths::opInstanceOfSlow(callFrame, value, baseVal, proto); + ASSERT(!value.isObject() || !proto.isObject()); + + bool result = JSObject::defaultHasInstance(callFrame, value, proto); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(jsBoolean(result)); } diff --git a/Source/JavaScriptCore/jit/JITStubs.h b/Source/JavaScriptCore/jit/JITStubs.h index e3ef4416e..a4619c816 100644 --- a/Source/JavaScriptCore/jit/JITStubs.h +++ b/Source/JavaScriptCore/jit/JITStubs.h @@ -350,6 +350,7 @@ extern "C" { EncodedJSValue JIT_STUB cti_op_call_NotJSFunction(STUB_ARGS_DECLARATION) WTF_INTERNAL; EncodedJSValue JIT_STUB cti_op_call_eval(STUB_ARGS_DECLARATION) WTF_INTERNAL; EncodedJSValue JIT_STUB cti_op_construct_NotJSConstruct(STUB_ARGS_DECLARATION) WTF_INTERNAL; + EncodedJSValue JIT_STUB cti_op_check_has_instance(STUB_ARGS_DECLARATION) WTF_INTERNAL; EncodedJSValue JIT_STUB cti_op_create_this(STUB_ARGS_DECLARATION) WTF_INTERNAL; EncodedJSValue JIT_STUB cti_op_convert_this(STUB_ARGS_DECLARATION) WTF_INTERNAL; EncodedJSValue JIT_STUB cti_op_create_arguments(STUB_ARGS_DECLARATION) WTF_INTERNAL; @@ -431,7 +432,6 @@ extern "C" { void* JIT_STUB cti_op_load_varargs(STUB_ARGS_DECLARATION) WTF_INTERNAL; int JIT_STUB cti_timeout_check(STUB_ARGS_DECLARATION) WTF_INTERNAL; int JIT_STUB cti_has_property(STUB_ARGS_DECLARATION) WTF_INTERNAL; - void JIT_STUB cti_op_check_has_instance(STUB_ARGS_DECLARATION) WTF_INTERNAL; void JIT_STUB cti_op_debug(STUB_ARGS_DECLARATION) WTF_INTERNAL; void JIT_STUB cti_op_end(STUB_ARGS_DECLARATION) WTF_INTERNAL; void JIT_STUB cti_op_jmp_scopes(STUB_ARGS_DECLARATION) WTF_INTERNAL; diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp index 1ddfca37c..f9833e4ce 100644 --- a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp +++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp @@ -301,11 +301,13 @@ inline bool jitCompileAndSetHeuristics(CodeBlock* codeBlock, ExecState* exec) } enum EntryKind { Prologue, ArityCheck }; -static SlowPathReturnType entryOSR(ExecState* exec, Instruction* pc, CodeBlock* codeBlock, const char *name, EntryKind kind) +static SlowPathReturnType entryOSR(ExecState* exec, Instruction*, CodeBlock* codeBlock, const char *name, EntryKind kind) { #if ENABLE(JIT_VERBOSE_OSR) dataLog("%p: Entered %s with executeCounter = %s\n", codeBlock, name, codeBlock->llintExecuteCounter().status()); +#else + UNUSED_PARAM(name); #endif if (!shouldJIT(exec)) { @@ -718,19 +720,27 @@ LLINT_SLOW_PATH_DECL(slow_path_bitxor) LLINT_SLOW_PATH_DECL(slow_path_check_has_instance) { LLINT_BEGIN(); - JSValue baseVal = LLINT_OP_C(1).jsValue(); -#ifndef NDEBUG - TypeInfo typeInfo(UnspecifiedType); - ASSERT(!baseVal.isObject() - || !(typeInfo = asObject(baseVal)->structure()->typeInfo()).implementsHasInstance()); -#endif + + JSValue value = LLINT_OP_C(2).jsValue(); + JSValue baseVal = LLINT_OP_C(3).jsValue(); + if (baseVal.isObject()) { + JSObject* baseObject = asObject(baseVal); + ASSERT(!baseObject->structure()->typeInfo().implementsDefaultHasInstance()); + if (baseObject->structure()->typeInfo().implementsHasInstance()) { + pc += pc[4].u.operand; + LLINT_RETURN(jsBoolean(baseObject->methodTable()->customHasInstance(baseObject, exec, value))); + } + } LLINT_THROW(createInvalidParamError(exec, "instanceof", baseVal)); } LLINT_SLOW_PATH_DECL(slow_path_instanceof) { LLINT_BEGIN(); - LLINT_RETURN(jsBoolean(CommonSlowPaths::opInstanceOfSlow(exec, LLINT_OP_C(2).jsValue(), LLINT_OP_C(3).jsValue(), LLINT_OP_C(4).jsValue()))); + JSValue value = LLINT_OP_C(2).jsValue(); + JSValue proto = LLINT_OP_C(3).jsValue(); + ASSERT(!value.isObject() || !proto.isObject()); + LLINT_RETURN(jsBoolean(JSObject::defaultHasInstance(exec, value, proto))); } LLINT_SLOW_PATH_DECL(slow_path_typeof) diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm index 953bb3a92..53da6424b 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm @@ -833,28 +833,21 @@ _llint_op_bitor: _llint_op_check_has_instance: traceExecution() - loadi 4[PC], t1 + loadi 12[PC], t1 loadConstantOrVariablePayload(t1, CellTag, t0, .opCheckHasInstanceSlow) loadp JSCell::m_structure[t0], t0 - btbz Structure::m_typeInfo + TypeInfo::m_flags[t0], ImplementsHasInstance, .opCheckHasInstanceSlow - dispatch(2) + btbz Structure::m_typeInfo + TypeInfo::m_flags[t0], ImplementsDefaultHasInstance, .opCheckHasInstanceSlow + dispatch(5) .opCheckHasInstanceSlow: callSlowPath(_llint_slow_path_check_has_instance) - dispatch(2) + dispatch(0) _llint_op_instanceof: traceExecution() - # Check that baseVal implements the default HasInstance behavior. - # FIXME: This should be deprecated. - loadi 12[PC], t1 - loadConstantOrVariablePayloadUnchecked(t1, t0) - loadp JSCell::m_structure[t0], t0 - btbz Structure::m_typeInfo + TypeInfo::m_flags[t0], ImplementsDefaultHasInstance, .opInstanceofSlow - # Actually do the work. - loadi 16[PC], t0 + loadi 12[PC], t0 loadi 4[PC], t3 loadConstantOrVariablePayload(t0, CellTag, t1, .opInstanceofSlow) loadp JSCell::m_structure[t1], t2 @@ -874,11 +867,11 @@ _llint_op_instanceof: .opInstanceofDone: storei BooleanTag, TagOffset[cfr, t3, 8] storei t0, PayloadOffset[cfr, t3, 8] - dispatch(5) + dispatch(4) .opInstanceofSlow: callSlowPath(_llint_slow_path_instanceof) - dispatch(5) + dispatch(4) _llint_op_is_undefined: diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm index 812be0ec9..f4ff5c464 100644 --- a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm +++ b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm @@ -691,28 +691,21 @@ _llint_op_bitor: _llint_op_check_has_instance: traceExecution() - loadis 8[PB, PC, 8], t1 + loadis 24[PB, PC, 8], t1 loadConstantOrVariableCell(t1, t0, .opCheckHasInstanceSlow) loadp JSCell::m_structure[t0], t0 - btbz Structure::m_typeInfo + TypeInfo::m_flags[t0], ImplementsHasInstance, .opCheckHasInstanceSlow - dispatch(2) + btbz Structure::m_typeInfo + TypeInfo::m_flags[t0], ImplementsDefaultHasInstance, .opCheckHasInstanceSlow + dispatch(5) .opCheckHasInstanceSlow: callSlowPath(_llint_slow_path_check_has_instance) - dispatch(2) + dispatch(0) _llint_op_instanceof: traceExecution() - # Check that baseVal implements the default HasInstance behavior. - # FIXME: This should be deprecated. - loadis 24[PB, PC, 8], t1 - loadConstantOrVariable(t1, t0) - loadp JSCell::m_structure[t0], t0 - btbz Structure::m_typeInfo + TypeInfo::m_flags[t0], ImplementsDefaultHasInstance, .opInstanceofSlow - # Actually do the work. - loadis 32[PB, PC, 8], t0 + loadis 24[PB, PC, 8], t0 loadis 8[PB, PC, 8], t3 loadConstantOrVariableCell(t0, t1, .opInstanceofSlow) loadp JSCell::m_structure[t1], t2 @@ -732,11 +725,11 @@ _llint_op_instanceof: .opInstanceofDone: orp ValueFalse, t0 storep t0, [cfr, t3, 8] - dispatch(5) + dispatch(4) .opInstanceofSlow: callSlowPath(_llint_slow_path_instanceof) - dispatch(5) + dispatch(4) _llint_op_is_undefined: diff --git a/Source/JavaScriptCore/offlineasm/armv7.rb b/Source/JavaScriptCore/offlineasm/armv7.rb index b05f0e57f..d9f9bfa01 100644 --- a/Source/JavaScriptCore/offlineasm/armv7.rb +++ b/Source/JavaScriptCore/offlineasm/armv7.rb @@ -353,7 +353,7 @@ def armV7LowerMisplacedImmediates(list) | node | if node.is_a? Instruction case node.opcode - when "storei", "storep" + when "storeb", "storei", "storep" operands = node.operands newOperands = [] operands.each { diff --git a/Source/JavaScriptCore/offlineasm/cloop.rb b/Source/JavaScriptCore/offlineasm/cloop.rb index 8469ed441..9975e0767 100644 --- a/Source/JavaScriptCore/offlineasm/cloop.rb +++ b/Source/JavaScriptCore/offlineasm/cloop.rb @@ -578,7 +578,7 @@ class Instruction when "loadbs" $asm.putc "#{operands[1].clValue(:int)} = #{operands[0].int8MemRef};" when "storeb" - $asm.putc "#{operands[1].uint8MemRef} = #{operands[0].clValue(:int8)}" + $asm.putc "#{operands[1].uint8MemRef} = #{operands[0].clValue(:int8)};" when "loadh" $asm.putc "#{operands[1].clValue(:int)} = #{operands[0].uint16MemRef};" when "loadhs" diff --git a/Source/JavaScriptCore/runtime/Arguments.cpp b/Source/JavaScriptCore/runtime/Arguments.cpp index e5e503ee1..fdf202192 100644 --- a/Source/JavaScriptCore/runtime/Arguments.cpp +++ b/Source/JavaScriptCore/runtime/Arguments.cpp @@ -343,6 +343,18 @@ void Arguments::tearOff(CallFrame* callFrame) m_registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[m_numArguments]); m_registers = m_registerArray.get() + CallFrame::offsetFor(m_numArguments + 1); + // If we have a captured argument that logically aliases activation storage, + // but we optimize away the activation, the argument needs to tear off into + // our storage. The simplest way to do this is to revert it to Normal status. + if (m_slowArguments && !m_activation) { + for (size_t i = 0; i < m_numArguments; ++i) { + if (m_slowArguments[i].status != SlowArgument::Captured) + continue; + m_slowArguments[i].status = SlowArgument::Normal; + m_slowArguments[i].index = CallFrame::argumentOffset(i); + } + } + if (!callFrame->isInlineCallFrame()) { for (size_t i = 0; i < m_numArguments; ++i) trySetArgument(callFrame->globalData(), i, callFrame->argumentAfterCapture(i)); @@ -362,20 +374,8 @@ void Arguments::didTearOffActivation(ExecState* exec, JSActivation* activation) if (!m_numArguments) return; - tearOff(exec); - - SharedSymbolTable* symbolTable = activation->symbolTable(); - const SlowArgument* slowArguments = symbolTable->slowArguments(); - if (!slowArguments) - return; - - ASSERT(symbolTable->captureMode() == SharedSymbolTable::AllOfTheThings); m_activation.set(exec->globalData(), this, activation); - - allocateSlowArguments(); - size_t count = min<unsigned>(m_numArguments, symbolTable->parameterCount()); - for (size_t i = 0; i < count; ++i) - m_slowArguments[i] = slowArguments[i]; + tearOff(exec); } void Arguments::tearOff(CallFrame* callFrame, InlineCallFrame* inlineCallFrame) diff --git a/Source/JavaScriptCore/runtime/Arguments.h b/Source/JavaScriptCore/runtime/Arguments.h index c9d0d503d..40063bead 100644 --- a/Source/JavaScriptCore/runtime/Arguments.h +++ b/Source/JavaScriptCore/runtime/Arguments.h @@ -161,6 +161,10 @@ namespace JSC { if (m_slowArguments) return; m_slowArguments = adoptArrayPtr(new SlowArgument[m_numArguments]); + for (size_t i = 0; i < m_numArguments; ++i) { + ASSERT(m_slowArguments[i].status == SlowArgument::Normal); + m_slowArguments[i].index = CallFrame::argumentOffset(i); + } } inline bool Arguments::tryDeleteArgument(size_t argument) @@ -210,14 +214,14 @@ namespace JSC { inline WriteBarrierBase<Unknown>& Arguments::argument(size_t argument) { ASSERT(isArgument(argument)); - if (!m_slowArguments || m_slowArguments[argument].status == SlowArgument::Normal) + if (!m_slowArguments) return m_registers[CallFrame::argumentOffset(argument)]; - ASSERT(m_slowArguments[argument].status == SlowArgument::Captured); - if (!m_activation) - return m_registers[m_slowArguments[argument].indexIfCaptured]; + int index = m_slowArguments[argument].index; + if (!m_activation || m_slowArguments[argument].status != SlowArgument::Captured) + return m_registers[index]; - return m_activation->registerAt(m_slowArguments[argument].indexIfCaptured); + return m_activation->registerAt(index); } inline void Arguments::finishCreation(CallFrame* callFrame) @@ -234,6 +238,15 @@ namespace JSC { m_overrodeCaller = false; m_isStrictMode = callFrame->codeBlock()->isStrictMode(); + SharedSymbolTable* symbolTable = callFrame->codeBlock()->symbolTable(); + const SlowArgument* slowArguments = symbolTable->slowArguments(); + if (slowArguments) { + allocateSlowArguments(); + size_t count = std::min<unsigned>(m_numArguments, symbolTable->parameterCount()); + for (size_t i = 0; i < count; ++i) + m_slowArguments[i] = slowArguments[i]; + } + // The bytecode generator omits op_tear_off_activation in cases of no // declared parameters, so we need to tear off immediately. if (m_isStrictMode || !callee->jsExecutable()->parameterCount()) @@ -254,6 +267,8 @@ namespace JSC { m_overrodeCaller = false; m_isStrictMode = jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->isStrictMode(); + ASSERT(!jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->symbolTable()->slowArguments()); + // The bytecode generator omits op_tear_off_activation in cases of no // declared parameters, so we need to tear off immediately. if (m_isStrictMode || !callee->jsExecutable()->parameterCount()) diff --git a/Source/JavaScriptCore/runtime/ArrayConventions.h b/Source/JavaScriptCore/runtime/ArrayConventions.h index af98e15fa..3ea6b0471 100644 --- a/Source/JavaScriptCore/runtime/ArrayConventions.h +++ b/Source/JavaScriptCore/runtime/ArrayConventions.h @@ -26,8 +26,6 @@ namespace JSC { -#define CHECK_ARRAY_CONSISTENCY 0 - // Overview of JSArray // // Properties of JSArray objects may be stored in one of three locations: diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp index c70e40d77..95cba0936 100644 --- a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp @@ -629,6 +629,15 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec) return JSValue::encode(result); } +inline JSValue getOrHole(JSObject* obj, ExecState* exec, unsigned propertyName) +{ + PropertySlot slot(obj); + if (obj->getPropertySlot(exec, propertyName, slot)) + return slot.getValue(exec, propertyName); + + return JSValue(); +} + EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec) { JSObject* thisObj = exec->hostThisValue().toObject(exec); @@ -653,17 +662,21 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec) // "Min" sort. Not the fastest, but definitely less code than heapsort // or quicksort, and much less swapping than bubblesort/insertionsort. for (unsigned i = 0; i < length - 1; ++i) { - JSValue iObj = thisObj->get(exec, i); + JSValue iObj = getOrHole(thisObj, exec, i); if (exec->hadException()) return JSValue::encode(jsUndefined()); unsigned themin = i; JSValue minObj = iObj; for (unsigned j = i + 1; j < length; ++j) { - JSValue jObj = thisObj->get(exec, j); + JSValue jObj = getOrHole(thisObj, exec, j); if (exec->hadException()) return JSValue::encode(jsUndefined()); double compareResult; - if (jObj.isUndefined()) + if (!jObj) + compareResult = 1; + else if (!minObj) + compareResult = -1; + else if (jObj.isUndefined()) compareResult = 1; // don't check minObj because there's no need to differentiate == (0) from > (1) else if (minObj.isUndefined()) compareResult = -1; @@ -682,12 +695,22 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec) } // Swap themin and i if (themin > i) { - thisObj->methodTable()->putByIndex(thisObj, exec, i, minObj, true); - if (exec->hadException()) + if (minObj) { + thisObj->methodTable()->putByIndex(thisObj, exec, i, minObj, true); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, i)) { + throwTypeError(exec, "Unable to delete property."); return JSValue::encode(jsUndefined()); - thisObj->methodTable()->putByIndex(thisObj, exec, themin, iObj, true); - if (exec->hadException()) + } + if (iObj) { + thisObj->methodTable()->putByIndex(thisObj, exec, themin, iObj, true); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, themin)) { + throwTypeError(exec, "Unable to delete property."); return JSValue::encode(jsUndefined()); + } } } return JSValue::encode(thisObj); @@ -730,7 +753,6 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec) return JSValue::encode(jsUndefined()); resObj->initializeIndex(globalData, k, v); } - resObj->completeInitialization(deleteCount); unsigned additionalArgs = std::max<int>(exec->argumentCount() - 2, 0); if (additionalArgs < deleteCount) { diff --git a/Source/JavaScriptCore/runtime/ArrayStorage.h b/Source/JavaScriptCore/runtime/ArrayStorage.h index d967d0b5a..1ab936335 100644 --- a/Source/JavaScriptCore/runtime/ArrayStorage.h +++ b/Source/JavaScriptCore/runtime/ArrayStorage.h @@ -64,10 +64,6 @@ public: m_sparseMap.copyFrom(other.m_sparseMap); m_indexBias = other.m_indexBias; m_numValuesInVector = other.m_numValuesInVector; -#if CHECK_ARRAY_CONSISTENCY - m_initializationIndex = other.m_initializationIndex; - m_inCompactInitialization = other.m_inCompactInitialization; -#endif } bool inSparseMode() @@ -78,11 +74,7 @@ public: WriteBarrier<SparseArrayValueMap> m_sparseMap; unsigned m_indexBias; unsigned m_numValuesInVector; -#if CHECK_ARRAY_CONSISTENCY - // Needs to be a uintptr_t for alignment purposes. - uintptr_t m_initializationIndex; - uintptr_t m_inCompactInitialization; -#elif USE(JSVALUE32_64) +#if USE(JSVALUE32_64) uintptr_t m_padding; #endif WriteBarrier<Unknown> m_vector[1]; diff --git a/Source/JavaScriptCore/runtime/ClassInfo.h b/Source/JavaScriptCore/runtime/ClassInfo.h index 0e1747b24..e8823d571 100644 --- a/Source/JavaScriptCore/runtime/ClassInfo.h +++ b/Source/JavaScriptCore/runtime/ClassInfo.h @@ -81,8 +81,8 @@ namespace JSC { typedef String (*ClassNameFunctionPtr)(const JSObject*); ClassNameFunctionPtr className; - typedef bool (*HasInstanceFunctionPtr)(JSObject*, ExecState*, JSValue, JSValue); - HasInstanceFunctionPtr hasInstance; + typedef bool (*CustomHasInstanceFunctionPtr)(JSObject*, ExecState*, JSValue); + CustomHasInstanceFunctionPtr customHasInstance; typedef void (*PutWithAttributesFunctionPtr)(JSObject*, ExecState*, PropertyName propertyName, JSValue, unsigned attributes); PutWithAttributesFunctionPtr putDirectVirtual; @@ -130,7 +130,7 @@ struct MemberCheck##member { \ &ClassName::getOwnNonIndexPropertyNames, \ &ClassName::getPropertyNames, \ &ClassName::className, \ - &ClassName::hasInstance, \ + &ClassName::customHasInstance, \ &ClassName::putDirectVirtual, \ &ClassName::defineOwnProperty, \ &ClassName::getOwnPropertyDescriptor, \ diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.h b/Source/JavaScriptCore/runtime/CommonSlowPaths.h index e4c76ad16..7edd9091c 100644 --- a/Source/JavaScriptCore/runtime/CommonSlowPaths.h +++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.h @@ -75,28 +75,6 @@ ALWAYS_INLINE ExecState* arityCheckFor(ExecState* exec, RegisterFile* registerFi return newExec; } -ALWAYS_INLINE bool opInstanceOfSlow(ExecState* exec, JSValue value, JSValue baseVal, JSValue proto) -{ - ASSERT(!value.isCell() || !baseVal.isCell() || !proto.isCell() - || !value.isObject() || !baseVal.isObject() || !proto.isObject() - || !asObject(baseVal)->structure()->typeInfo().implementsDefaultHasInstance()); - - - // ECMA-262 15.3.5.3: - // Throw an exception either if baseVal is not an object, or if it does not implement 'HasInstance' (i.e. is a function). - TypeInfo typeInfo(UnspecifiedType); - if (!baseVal.isObject() || !(typeInfo = asObject(baseVal)->structure()->typeInfo()).implementsHasInstance()) { - exec->globalData().exception = createInvalidParamError(exec, "instanceof", baseVal); - return false; - } - ASSERT(typeInfo.type() != UnspecifiedType); - - if (!typeInfo.overridesHasInstance() && !value.isObject()) - return false; - - return asObject(baseVal)->methodTable()->hasInstance(asObject(baseVal), exec, value, proto); -} - inline bool opIn(ExecState* exec, JSValue propName, JSValue baseVal) { if (!baseVal.isObject()) { diff --git a/Source/JavaScriptCore/runtime/DatePrototype.cpp b/Source/JavaScriptCore/runtime/DatePrototype.cpp index 62211d302..9b2cb164f 100644 --- a/Source/JavaScriptCore/runtime/DatePrototype.cpp +++ b/Source/JavaScriptCore/runtime/DatePrototype.cpp @@ -195,7 +195,7 @@ static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMil #elif USE(ICU_UNICODE) && !UCONFIG_NO_FORMATTING -static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, double timeInMilliseconds, LocaleDateTimeFormat format) +static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format) { UDateFormatStyle timeStyle = (format != LocaleDate ? UDAT_LONG : UDAT_NONE); UDateFormatStyle dateStyle = (format != LocaleTime ? UDAT_LONG : UDAT_NONE); diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp index 2791c65d4..d7327d564 100644 --- a/Source/JavaScriptCore/runtime/Executable.cpp +++ b/Source/JavaScriptCore/runtime/Executable.cpp @@ -135,7 +135,6 @@ const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExec FunctionExecutable::FunctionExecutable(JSGlobalData& globalData, FunctionBodyNode* node) : ScriptExecutable(globalData.functionExecutableStructure.get(), globalData, node->source(), node->isStrictMode()) - , m_numCapturedVariables(0) , m_forceUsesArguments(node->usesArguments()) , m_parameters(node->parameters()) , m_name(node->ident()) @@ -527,7 +526,6 @@ JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, JSScope* s m_numParametersForCall = m_codeBlockForCall->numParameters(); ASSERT(m_numParametersForCall); - m_numCapturedVariables = m_codeBlockForCall->m_numCapturedVars; m_symbolTable.set(exec->globalData(), this, m_codeBlockForCall->symbolTable()); #if ENABLE(JIT) @@ -570,7 +568,6 @@ JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, JSSco m_numParametersForConstruct = m_codeBlockForConstruct->numParameters(); ASSERT(m_numParametersForConstruct); - m_numCapturedVariables = m_codeBlockForConstruct->m_numCapturedVars; m_symbolTable.set(exec->globalData(), this, m_codeBlockForConstruct->symbolTable()); #if ENABLE(JIT) diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h index 76ed21d8b..808c78fba 100644 --- a/Source/JavaScriptCore/runtime/Executable.h +++ b/Source/JavaScriptCore/runtime/Executable.h @@ -692,7 +692,6 @@ namespace JSC { const Identifier& inferredName() { return m_inferredName; } JSString* nameValue() const { return m_nameValue.get(); } size_t parameterCount() const { return m_parameters->size(); } // Excluding 'this'! - unsigned capturedVariableCount() const { return m_numCapturedVariables; } String paramString() const; SharedSymbolTable* symbolTable() const { return m_symbolTable.get(); } @@ -742,8 +741,7 @@ namespace JSC { } static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags; - unsigned m_numCapturedVariables : 31; - bool m_forceUsesArguments : 1; + bool m_forceUsesArguments; RefPtr<FunctionParameters> m_parameters; OwnPtr<FunctionCodeBlock> m_codeBlockForCall; diff --git a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp index 455a21877..dd1628b29 100644 --- a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp +++ b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp @@ -193,7 +193,6 @@ EncodedJSValue JSC_HOST_CALL functionProtoFuncBind(ExecState* exec) for (size_t i = 0; i < numBoundArgs; ++i) boundArgs->initializeIndex(exec->globalData(), i, exec->argument(i + 1)); - boundArgs->completeInitialization(numBoundArgs); // If the [[Class]] internal property of Target is "Function", then ... // Else set the length own property of F to 0. diff --git a/Source/JavaScriptCore/runtime/JSActivation.cpp b/Source/JavaScriptCore/runtime/JSActivation.cpp index dc061bc57..c34e10bc8 100644 --- a/Source/JavaScriptCore/runtime/JSActivation.cpp +++ b/Source/JavaScriptCore/runtime/JSActivation.cpp @@ -53,7 +53,7 @@ void JSActivation::visitChildren(JSCell* cell, SlotVisitor& visitor) if (!thisObject->isTornOff()) return; - for (size_t i = 0; i < thisObject->storageSize(); ++i) + for (int i = 0; i < thisObject->symbolTable()->captureCount(); ++i) visitor.append(&thisObject->storage()[i]); } diff --git a/Source/JavaScriptCore/runtime/JSActivation.h b/Source/JavaScriptCore/runtime/JSActivation.h index 8211e7710..442941335 100644 --- a/Source/JavaScriptCore/runtime/JSActivation.h +++ b/Source/JavaScriptCore/runtime/JSActivation.h @@ -41,21 +41,20 @@ namespace JSC { class JSActivation : public JSVariableObject { private: - JSActivation(JSGlobalData& globalData, CallFrame*, SharedSymbolTable*, size_t storageSize); + JSActivation(JSGlobalData& globalData, CallFrame*, SharedSymbolTable*); public: typedef JSVariableObject Base; static JSActivation* create(JSGlobalData& globalData, CallFrame* callFrame, FunctionExecutable* functionExecutable) { - size_t storageSize = JSActivation::storageSize(functionExecutable->symbolTable()); JSActivation* activation = new ( NotNull, allocateCell<JSActivation>( globalData.heap, - allocationSize(storageSize) + allocationSize(functionExecutable->symbolTable()) ) - ) JSActivation(globalData, callFrame, functionExecutable->symbolTable(), storageSize); + ) JSActivation(globalData, callFrame, functionExecutable->symbolTable()); activation->finishCreation(globalData); return activation; } @@ -81,7 +80,9 @@ namespace JSC { static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(globalData, globalObject, proto, TypeInfo(ActivationObjectType, StructureFlags), &s_info); } - bool isValid(const SymbolTableEntry&); + WriteBarrierBase<Unknown>& registerAt(int) const; + bool isValidIndex(int) const; + bool isValid(const SymbolTableEntry&) const; bool isTornOff(); protected: @@ -97,19 +98,16 @@ namespace JSC { static JSValue argumentsGetter(ExecState*, JSValue, PropertyName); NEVER_INLINE PropertySlot::GetValueFunc getArgumentsGetter(); - static size_t allocationSize(size_t storageSize); - static size_t storageSize(SharedSymbolTable*); - static int captureStart(SharedSymbolTable*); + static size_t allocationSize(SharedSymbolTable*); int registerOffset(); - size_t storageSize(); - WriteBarrier<Unknown>* storage(); // storageSize() number of registers. + WriteBarrier<Unknown>* storage(); // captureCount() number of registers. }; extern int activationCount; extern int allTheThingsCount; - inline JSActivation::JSActivation(JSGlobalData& globalData, CallFrame* callFrame, SharedSymbolTable* symbolTable, size_t storageSize) + inline JSActivation::JSActivation(JSGlobalData& globalData, CallFrame* callFrame, SharedSymbolTable* symbolTable) : Base( globalData, callFrame->lexicalGlobalObject()->activationStructure(), @@ -119,7 +117,8 @@ namespace JSC { ) { WriteBarrier<Unknown>* storage = this->storage(); - for (size_t i = 0; i < storageSize; ++i) + size_t captureCount = symbolTable->captureCount(); + for (size_t i = 0; i < captureCount; ++i) new(&storage[i]) WriteBarrier<Unknown>; } @@ -142,26 +141,9 @@ namespace JSC { return false; } - inline int JSActivation::captureStart(SharedSymbolTable* symbolTable) - { - if (symbolTable->captureMode() == SharedSymbolTable::AllOfTheThings) - return -CallFrame::offsetFor(symbolTable->parameterCountIncludingThis()); - return symbolTable->captureStart(); - } - - inline size_t JSActivation::storageSize(SharedSymbolTable* symbolTable) - { - return symbolTable->captureEnd() - captureStart(symbolTable); - } - inline int JSActivation::registerOffset() { - return -captureStart(symbolTable()); - } - - inline size_t JSActivation::storageSize() - { - return storageSize(symbolTable()); + return -symbolTable()->captureStart(); } inline void JSActivation::tearOff(JSGlobalData& globalData) @@ -172,23 +154,9 @@ namespace JSC { WriteBarrierBase<Unknown>* dst = storage() + registerOffset; WriteBarrierBase<Unknown>* src = m_registers; - if (symbolTable()->captureMode() == SharedSymbolTable::AllOfTheThings) { - int from = -registerOffset; - int to = CallFrame::thisArgumentOffset(); // Skip 'this' because it's not lexically accessible. - for (int i = from; i < to; ++i) - dst[i].set(globalData, this, src[i].get()); - - dst[RegisterFile::ArgumentCount].set(globalData, this, JSValue( - CallFrame::create(reinterpret_cast<Register*>(src))->argumentCountIncludingThis())); - - int captureEnd = symbolTable()->captureEnd(); - for (int i = 0; i < captureEnd; ++i) - dst[i].set(globalData, this, src[i].get()); - } else { - int captureEnd = symbolTable()->captureEnd(); - for (int i = symbolTable()->captureStart(); i < captureEnd; ++i) - dst[i].set(globalData, this, src[i].get()); - } + int captureEnd = symbolTable()->captureEnd(); + for (int i = symbolTable()->captureStart(); i < captureEnd; ++i) + dst[i].set(globalData, this, src[i].get()); m_registers = dst; ASSERT(isTornOff()); @@ -207,22 +175,33 @@ namespace JSC { ); } - inline size_t JSActivation::allocationSize(size_t storageSize) + inline size_t JSActivation::allocationSize(SharedSymbolTable* symbolTable) { size_t objectSizeInBytes = WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(JSActivation)); - size_t storageSizeInBytes = storageSize * sizeof(WriteBarrier<Unknown>); + size_t storageSizeInBytes = symbolTable->captureCount() * sizeof(WriteBarrier<Unknown>); return objectSizeInBytes + storageSizeInBytes; } - inline bool JSActivation::isValid(const SymbolTableEntry& entry) + inline bool JSActivation::isValidIndex(int index) const { - if (entry.getIndex() < captureStart(symbolTable())) + if (index < symbolTable()->captureStart()) return false; - if (entry.getIndex() >= symbolTable()->captureEnd()) + if (index >= symbolTable()->captureEnd()) return false; return true; } + inline bool JSActivation::isValid(const SymbolTableEntry& entry) const + { + return isValidIndex(entry.getIndex()); + } + + inline WriteBarrierBase<Unknown>& JSActivation::registerAt(int index) const + { + ASSERT(isValidIndex(index)); + return Base::registerAt(index); + } + } // namespace JSC #endif // JSActivation_h diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp index ebbbd41aa..609781c65 100644 --- a/Source/JavaScriptCore/runtime/JSArray.cpp +++ b/Source/JavaScriptCore/runtime/JSArray.cpp @@ -60,10 +60,6 @@ Butterfly* createArrayButterflyInDictionaryIndexingMode(JSGlobalData& globalData storage->m_indexBias = 0; storage->m_sparseMap.clear(); storage->m_numValuesInVector = 0; -#if CHECK_ARRAY_CONSISTENCY - storage->m_initializationIndex = 0; - storage->m_inCompactInitialization = 0; -#endif return butterfly; } @@ -330,8 +326,6 @@ bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, unsigned count) bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException) { - checkIndexingConsistency(); - ArrayStorage* storage = ensureArrayStorage(exec->globalData()); unsigned length = storage->length(); @@ -392,14 +386,11 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException storage->setLength(newLength); - checkIndexingConsistency(); return true; } JSValue JSArray::pop(ExecState* exec) { - checkIndexingConsistency(); - switch (structure()->indexingType()) { case ArrayClass: return jsUndefined(); @@ -424,7 +415,6 @@ JSValue JSArray::pop(ExecState* exec) ASSERT(isLengthWritable()); storage->setLength(index); - checkIndexingConsistency(); return element; } } @@ -441,7 +431,6 @@ JSValue JSArray::pop(ExecState* exec) // Call the [[Put]] internal method of O with arguments "length", indx, and true. setLength(exec, index, true); // Return element. - checkIndexingConsistency(); return element; } @@ -456,8 +445,6 @@ JSValue JSArray::pop(ExecState* exec) // - pushing to an array of length 2^32-1 stores the property, but throws a range error. void JSArray::push(ExecState* exec, JSValue value) { - checkIndexingConsistency(); - switch (structure()->indexingType()) { case ArrayClass: { putByIndexBeyondVectorLengthWithArrayStorage(exec, 0, value, true, createInitialArrayStorage(exec->globalData())); @@ -483,7 +470,6 @@ void JSArray::push(ExecState* exec, JSValue value) storage->m_vector[length].set(exec->globalData(), this, value); storage->setLength(length + 1); ++storage->m_numValuesInVector; - checkIndexingConsistency(); return; } @@ -498,7 +484,6 @@ void JSArray::push(ExecState* exec, JSValue value) // Handled the same as putIndex. putByIndexBeyondVectorLengthWithArrayStorage(exec, storage->length(), value, true, storage); - checkIndexingConsistency(); break; } @@ -622,7 +607,6 @@ void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType cal // side-effect from swapping the order of equal primitive values. qsort(storage->m_vector, size, sizeof(WriteBarrier<Unknown>), compareNumbersForQSort); - checkIndexingConsistency(SortConsistencyCheck); return; } @@ -711,7 +695,6 @@ void JSArray::sort(ExecState* exec) Heap::heap(this)->popTempSortVector(&values); - checkIndexingConsistency(SortConsistencyCheck); return; } @@ -807,7 +790,6 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, case ArrayWithArrayStorage: { ArrayStorage* storage = m_butterfly->arrayStorage(); - checkIndexingConsistency(); // FIXME: This ignores exceptions raised in the compare function or in toNumber. @@ -912,7 +894,6 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, storage->m_numValuesInVector = newUsedVectorLength; - checkIndexingConsistency(SortConsistencyCheck); return; } @@ -983,8 +964,6 @@ unsigned JSArray::compactForSorting(JSGlobalData& globalData) { ASSERT(!inSparseIndexingMode()); - checkIndexingConsistency(); - switch (structure()->indexingType()) { case ArrayClass: return 0; @@ -1040,8 +1019,6 @@ unsigned JSArray::compactForSorting(JSGlobalData& globalData) storage->m_numValuesInVector = newUsedVectorLength; - checkIndexingConsistency(SortConsistencyCheck); - return numDefined; } diff --git a/Source/JavaScriptCore/runtime/JSArray.h b/Source/JavaScriptCore/runtime/JSArray.h index c46e67863..6e539c9db 100644 --- a/Source/JavaScriptCore/runtime/JSArray.h +++ b/Source/JavaScriptCore/runtime/JSArray.h @@ -51,7 +51,6 @@ namespace JSC { // contents are known at time of creation. Clients of this interface must: // - null-check the result (indicating out of memory, or otherwise unable to allocate vector). // - call 'initializeIndex' for all properties in sequence, for 0 <= i < initialLength. - // - called 'completeInitialization' after all properties have been initialized. static JSArray* tryCreateUninitialized(JSGlobalData&, Structure*, unsigned initialLength); JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool throwException); @@ -115,10 +114,6 @@ namespace JSC { storage->m_indexBias = 0; storage->m_sparseMap.clear(); storage->m_numValuesInVector = 0; -#if CHECK_ARRAY_CONSISTENCY - storage->m_initializationIndex = 0; - storage->m_inCompactInitialization = 0; -#endif return butterfly; } @@ -147,10 +142,6 @@ namespace JSC { storage->m_indexBias = 0; storage->m_sparseMap.clear(); storage->m_numValuesInVector = initialLength; -#if CHECK_ARRAY_CONSISTENCY - storage->m_initializationIndex = 0; - storage->m_inCompactInitialization = true; -#endif JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure, butterfly); array->finishCreation(globalData); @@ -187,7 +178,6 @@ namespace JSC { for (unsigned i = 0; i < length; ++i) array->initializeIndex(globalData, i, values.at(i)); - array->completeInitialization(length); return array; } @@ -204,7 +194,6 @@ namespace JSC { for (unsigned i = 0; i < length; ++i) array->initializeIndex(globalData, i, values[i]); - array->completeInitialization(length); return array; } diff --git a/Source/JavaScriptCore/runtime/JSBoundFunction.cpp b/Source/JavaScriptCore/runtime/JSBoundFunction.cpp index 08d6831c0..3815c144e 100644 --- a/Source/JavaScriptCore/runtime/JSBoundFunction.cpp +++ b/Source/JavaScriptCore/runtime/JSBoundFunction.cpp @@ -89,14 +89,9 @@ JSBoundFunction* JSBoundFunction::create(ExecState* exec, JSGlobalObject* global return function; } -bool JSBoundFunction::hasInstance(JSObject* object, ExecState* exec, JSValue value, JSValue) +bool JSBoundFunction::customHasInstance(JSObject* object, ExecState* exec, JSValue value) { - JSBoundFunction* thisObject = jsCast<JSBoundFunction*>(object); - // FIXME: our instanceof implementation will have already (incorrectly) performed - // a [[Get]] of .prototype from the bound function object, which is incorrect! - // https://bugs.webkit.org/show_bug.cgi?id=68656 - JSValue proto = thisObject->m_targetFunction->get(exec, exec->propertyNames().prototype); - return thisObject->m_targetFunction->methodTable()->hasInstance(thisObject->m_targetFunction.get(), exec, value, proto); + return jsCast<JSBoundFunction*>(object)->m_targetFunction->hasInstance(exec, value); } JSBoundFunction::JSBoundFunction(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, JSObject* targetFunction, JSValue boundThis, JSValue boundArgs) diff --git a/Source/JavaScriptCore/runtime/JSBoundFunction.h b/Source/JavaScriptCore/runtime/JSBoundFunction.h index 5067d194c..05a6ad8e1 100644 --- a/Source/JavaScriptCore/runtime/JSBoundFunction.h +++ b/Source/JavaScriptCore/runtime/JSBoundFunction.h @@ -39,7 +39,7 @@ public: static JSBoundFunction* create(ExecState*, JSGlobalObject*, JSObject* targetFunction, JSValue boundThis, JSValue boundArgs, int, const String&); - static bool hasInstance(JSObject*, ExecState*, JSValue, JSValue proto); + static bool customHasInstance(JSObject*, ExecState*, JSValue); JSObject* targetFunction() { return m_targetFunction.get(); } JSValue boundThis() { return m_boundThis.get(); } diff --git a/Source/JavaScriptCore/runtime/JSCell.cpp b/Source/JavaScriptCore/runtime/JSCell.cpp index e050a53ef..739247fb2 100644 --- a/Source/JavaScriptCore/runtime/JSCell.cpp +++ b/Source/JavaScriptCore/runtime/JSCell.cpp @@ -199,7 +199,7 @@ void JSCell::getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, Enumera ASSERT_NOT_REACHED(); } -bool JSCell::hasInstance(JSObject*, ExecState*, JSValue, JSValue) +bool JSCell::customHasInstance(JSObject*, ExecState*, JSValue) { ASSERT_NOT_REACHED(); return false; diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h index d6abcba99..cf6f4ec45 100644 --- a/Source/JavaScriptCore/runtime/JSCell.h +++ b/Source/JavaScriptCore/runtime/JSCell.h @@ -160,7 +160,7 @@ namespace JSC { static NO_RETURN_DUE_TO_ASSERT void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); static NO_RETURN_DUE_TO_ASSERT void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); static String className(const JSObject*); - static bool hasInstance(JSObject*, ExecState*, JSValue, JSValue prototypeProperty); + JS_EXPORT_PRIVATE static bool customHasInstance(JSObject*, ExecState*, JSValue); static NO_RETURN_DUE_TO_ASSERT void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes); static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow); static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp index 27f68e55b..3d643a266 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -310,9 +310,9 @@ void JSGlobalObject::reset(JSValue prototype) putDirectWithoutTransition(exec->globalData(), exec->propertyNames().eval, m_evalFunction.get(), DontEnum); putDirectWithoutTransition(exec->globalData(), Identifier(exec, "JSON"), JSONObject::create(exec, this, JSONObject::createStructure(exec->globalData(), this, m_objectPrototype.get())), DontEnum); + putDirectWithoutTransition(exec->globalData(), Identifier(exec, "Math"), MathObject::create(exec, this, MathObject::createStructure(exec->globalData(), this, m_objectPrototype.get())), DontEnum); GlobalPropertyInfo staticGlobals[] = { - GlobalPropertyInfo(Identifier(exec, "Math"), MathObject::create(exec, this, MathObject::createStructure(exec->globalData(), this, m_objectPrototype.get())), DontEnum | DontDelete), GlobalPropertyInfo(Identifier(exec, "NaN"), jsNaN(), DontEnum | DontDelete | ReadOnly), GlobalPropertyInfo(Identifier(exec, "Infinity"), jsNumber(std::numeric_limits<double>::infinity()), DontEnum | DontDelete | ReadOnly), GlobalPropertyInfo(Identifier(exec, "undefined"), jsUndefined(), DontEnum | DontDelete | ReadOnly) diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp index 229d1aea6..acff8a6ae 100644 --- a/Source/JavaScriptCore/runtime/JSObject.cpp +++ b/Source/JavaScriptCore/runtime/JSObject.cpp @@ -341,7 +341,6 @@ void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSV void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow) { JSObject* thisObject = jsCast<JSObject*>(cell); - thisObject->checkIndexingConsistency(); if (propertyName > MAX_ARRAY_INDEX) { PutPropertySlot slot(shouldThrow); @@ -372,7 +371,6 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, ++storage->m_numValuesInVector; valueSlot.set(exec->globalData(), thisObject, value); - thisObject->checkIndexingConsistency(); return; } @@ -400,7 +398,6 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, } valueSlot.set(exec->globalData(), thisObject, value); - thisObject->checkIndexingConsistency(); return; } @@ -409,7 +406,6 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, } thisObject->putByIndexBeyondVectorLength(exec, propertyName, value, shouldThrow); - thisObject->checkIndexingConsistency(); } ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(JSGlobalData& globalData, ArrayStorage* storage) @@ -485,10 +481,6 @@ ArrayStorage* JSObject::createArrayStorage(JSGlobalData& globalData, unsigned le result->m_sparseMap.clear(); result->m_numValuesInVector = 0; result->m_indexBias = 0; -#if CHECK_ARRAY_CONSISTENCY - result->m_initializationIndex = 0; - result->m_inCompactInitialization = 0; -#endif Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), structure()->suggestedIndexingTransition()); setButterfly(globalData, newButterfly, newStructure); return result; @@ -717,7 +709,6 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i) } } - thisObject->checkIndexingConsistency(); return true; } @@ -792,7 +783,18 @@ const HashEntry* JSObject::findPropertyHashEntry(ExecState* exec, PropertyName p return 0; } -bool JSObject::hasInstance(JSObject*, ExecState* exec, JSValue value, JSValue proto) +bool JSObject::hasInstance(ExecState* exec, JSValue value) +{ + TypeInfo info = structure()->typeInfo(); + if (info.implementsDefaultHasInstance()) + return defaultHasInstance(exec, value, get(exec, exec->propertyNames().prototype)); + if (info.implementsHasInstance()) + return methodTable()->customHasInstance(this, exec, value); + throwError(exec, createInvalidParamError(exec, "instanceof" , this)); + return false; +} + +bool JSObject::defaultHasInstance(ExecState* exec, JSValue value, JSValue proto) { if (!value.isObject()) return false; @@ -1570,49 +1572,6 @@ bool JSObject::increaseVectorLength(JSGlobalData& globalData, unsigned newLength return true; } -#if CHECK_ARRAY_CONSISTENCY -void JSObject::checkIndexingConsistency(ConsistencyCheckType type) -{ - ArrayStorage* storage = arrayStorageOrNull(); - if (!storage) - return; - - ASSERT(!storage->m_inCompactInitialization); - - ASSERT(storage); - if (type == SortConsistencyCheck) - ASSERT(!storage->m_sparseMap); - - unsigned numValuesInVector = 0; - for (unsigned i = 0; i < storage->vectorLength(); ++i) { - if (JSValue value = storage->m_vector[i].get()) { - ASSERT(i < storage->length()); - if (type != DestructorConsistencyCheck) - value.isUndefined(); // Likely to crash if the object was deallocated. - ++numValuesInVector; - } else { - if (type == SortConsistencyCheck) - ASSERT(i >= storage->m_numValuesInVector); - } - } - ASSERT(numValuesInVector == storage->m_numValuesInVector); - ASSERT(numValuesInVector <= storage->length()); - - if (m_sparseValueMap) { - SparseArrayValueMap::const_iterator end = m_sparseValueMap->end(); - for (SparseArrayValueMap::const_iterator it = m_sparseValueMap->begin(); it != end; ++it) { - unsigned index = it->first; - ASSERT(index < storage->length()); - ASSERT(index >= storage->vectorLength()); - ASSERT(index <= MAX_ARRAY_INDEX); - ASSERT(it->second); - if (type != DestructorConsistencyCheck) - it->second.getNonSparseMode().isUndefined(); // Likely to crash if the object was deallocated. - } - } -} -#endif // CHECK_ARRAY_CONSISTENCY - Butterfly* JSObject::growOutOfLineStorage(JSGlobalData& globalData, size_t oldSize, size_t newSize) { ASSERT(newSize > oldSize); diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h index bf2dae20d..bb59eb32b 100644 --- a/Source/JavaScriptCore/runtime/JSObject.h +++ b/Source/JavaScriptCore/runtime/JSObject.h @@ -259,15 +259,6 @@ namespace JSC { switch (structure()->indexingType()) { case ALL_ARRAY_STORAGE_INDEXING_TYPES: { ArrayStorage* storage = m_butterfly->arrayStorage(); -#if CHECK_ARRAY_CONSISTENCY - ASSERT(storage->m_inCompactInitialization); - // Check that we are initializing the next index in sequence. - ASSERT(i == storage->m_initializationIndex); - // tryCreateUninitialized set m_numValuesInVector to the initialLength, - // check we do not try to initialize more than this number of properties. - ASSERT(storage->m_initializationIndex < storage->m_numValuesInVector); - storage->m_initializationIndex++; -#endif ASSERT(i < storage->length()); ASSERT(i < storage->m_numValuesInVector); storage->m_vector[i].set(globalData, this, v); @@ -278,27 +269,6 @@ namespace JSC { } } - void completeInitialization(unsigned newLength) - { - switch (structure()->indexingType()) { - case ALL_ARRAY_STORAGE_INDEXING_TYPES: { - ArrayStorage* storage = m_butterfly->arrayStorage(); - // Check that we have initialized as meny properties as we think we have. - UNUSED_PARAM(storage); - ASSERT_UNUSED(newLength, newLength == storage->length()); -#if CHECK_ARRAY_CONSISTENCY - // Check that the number of propreties initialized matches the initialLength. - ASSERT(storage->m_initializationIndex == m_storage->m_numValuesInVector); - ASSERT(storage->m_inCompactInitialization); - storage->m_inCompactInitialization = false; -#endif - break; - } - default: - ASSERT_NOT_REACHED(); - } - } - bool inSparseIndexingMode() { switch (structure()->indexingType()) { @@ -336,7 +306,8 @@ namespace JSC { JS_EXPORT_PRIVATE static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType); - JS_EXPORT_PRIVATE static bool hasInstance(JSObject*, ExecState*, JSValue, JSValue prototypeProperty); + bool hasInstance(ExecState*, JSValue); + static bool defaultHasInstance(ExecState*, JSValue, JSValue prototypeProperty); JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); @@ -591,13 +562,6 @@ namespace JSC { bool defineOwnNonIndexProperty(ExecState*, PropertyName, PropertyDescriptor&, bool throwException); - enum ConsistencyCheckType { NormalConsistencyCheck, DestructorConsistencyCheck, SortConsistencyCheck }; -#if !CHECK_ARRAY_CONSISTENCY - void checkIndexingConsistency(ConsistencyCheckType = NormalConsistencyCheck) { } -#else - void checkIndexingConsistency(ConsistencyCheckType = NormalConsistencyCheck); -#endif - void putByIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, bool shouldThrow, ArrayStorage*); bool increaseVectorLength(JSGlobalData&, unsigned newLength); diff --git a/Source/JavaScriptCore/runtime/Options.cpp b/Source/JavaScriptCore/runtime/Options.cpp index 16c0b5d43..b164948a5 100644 --- a/Source/JavaScriptCore/runtime/Options.cpp +++ b/Source/JavaScriptCore/runtime/Options.cpp @@ -35,6 +35,7 @@ #include <wtf/PageBlock.h> #include <wtf/StdLibExtras.h> #include <wtf/StringExtras.h> +#include <wtf/UnusedParam.h> #if OS(DARWIN) && ENABLE(PARALLEL_GC) #include <sys/sysctl.h> @@ -101,6 +102,8 @@ static unsigned computeNumberOfGCMarkers(int maxNumberOfGCMarkers) ASSERT(cpusToUse >= 1); if (cpusToUse < 1) cpusToUse = 1; +#else + UNUSED_PARAM(maxNumberOfGCMarkers); #endif return cpusToUse; diff --git a/Source/JavaScriptCore/runtime/SymbolTable.h b/Source/JavaScriptCore/runtime/SymbolTable.h index 5427a009b..6063dbab4 100644 --- a/Source/JavaScriptCore/runtime/SymbolTable.h +++ b/Source/JavaScriptCore/runtime/SymbolTable.h @@ -49,12 +49,12 @@ namespace JSC { SlowArgument() : status(Normal) - , indexIfCaptured(0) + , index(0) { } Status status; - int indexIfCaptured; // If status is 'Captured', indexIfCaptured is our index in the CallFrame. + int index; // If status is 'Deleted', index is bogus. }; static ALWAYS_INLINE int missingSymbolMarker() { return std::numeric_limits<int>::max(); } @@ -360,20 +360,14 @@ namespace JSC { bool usesNonStrictEval() { return m_usesNonStrictEval; } void setUsesNonStrictEval(bool usesNonStrictEval) { m_usesNonStrictEval = usesNonStrictEval; } - enum CaptureMode { - SomeOfTheThings, - AllOfTheThings - }; - - CaptureMode captureMode() { return m_captureMode; } - void setCaptureMode(CaptureMode captureMode) { m_captureMode = captureMode; } - int captureStart() { return m_captureStart; } void setCaptureStart(int captureStart) { m_captureStart = captureStart; } int captureEnd() { return m_captureEnd; } void setCaptureEnd(int captureEnd) { m_captureEnd = captureEnd; } + int captureCount() { return m_captureEnd - m_captureStart; } + int parameterCount() { return m_parameterCountIncludingThis - 1; } int parameterCountIncludingThis() { return m_parameterCountIncludingThis; } void setParameterCountIncludingThis(int parameterCountIncludingThis) { m_parameterCountIncludingThis = parameterCountIncludingThis; } @@ -389,7 +383,6 @@ namespace JSC { : JSCell(globalData, globalData.sharedSymbolTableStructure.get()) , m_parameterCountIncludingThis(0) , m_usesNonStrictEval(false) - , m_captureMode(SomeOfTheThings) , m_captureStart(0) , m_captureEnd(0) { @@ -398,7 +391,6 @@ namespace JSC { int m_parameterCountIncludingThis; bool m_usesNonStrictEval; - CaptureMode m_captureMode; int m_captureStart; int m_captureEnd; diff --git a/Source/JavaScriptCore/tests/mozilla/expected.html b/Source/JavaScriptCore/tests/mozilla/expected.html index 06136de27..13c0139f5 100644 --- a/Source/JavaScriptCore/tests/mozilla/expected.html +++ b/Source/JavaScriptCore/tests/mozilla/expected.html @@ -9,9 +9,9 @@ Test List: All tests<br> Skip List: ecma/Date/15.9.2.1.js, ecma/Date/15.9.2.2-1.js, ecma/Date/15.9.2.2-2.js, ecma/Date/15.9.2.2-3.js, ecma/Date/15.9.2.2-4.js, ecma/Date/15.9.2.2-5.js, ecma/Date/15.9.2.2-6.js, ecma_3/Date/15.9.5.7.js, ecma/Date/15.9.5.14.js, ecma/Date/15.9.5.31-1.js, ecma/Date/15.9.5.34-1.js<br> 1124 test(s) selected, 1116 test(s) completed, 44 failures reported (3.94% failed)<br> Engine command line: "/Volumes/Data/Saxony/OpenSource/WebKitBuild/Debug/jsc" <br> -OS type: Darwin Bearclaw-Kaliber.local 12.0.0 Darwin Kernel Version 12.0.0: Sun Jun 24 23:00:16 PDT 2012; root:xnu-2050.7.9~1/RELEASE_X86_64 x86_64<br> -Testcase execution time: 52 seconds.<br> -Tests completed on Thu Sep 6 15:11:19 2012.<br><br> +OS type: Darwin Bearclaw-Kaliber.local 12.0.0 Darwin Kernel Version 12.0.0: Fri Jun 22 20:01:10 PDT 2012; root:xnu-2050.7.7~1/RELEASE_X86_64 x86_64<br> +Testcase execution time: 54 seconds.<br> +Tests completed on Fri Sep 21 18:29:47 2012.<br><br> [ <a href='#fail_detail'>Failure Details</a> | <a href='#retest_list'>Retest List</a> | <a href='menu.html'>Test Selection Page</a> ]<br> <hr> <a name='fail_detail'></a> @@ -80,7 +80,7 @@ f.arity = undefined FAILED! expected: 3<br> Testcase terminated with signal 0<br> Complete testcase output was:<br> function-001.js functions not separated by semicolons are errors in version 120 and higher<br> -eval("function f(){}function g(){}") = undefined FAILED! expected: error<br> +eval("function f(){}function g(){}") = undefined PASSED!<br> </tt><br> <a name='failure9'></a><dd><b>Testcase <a target='other_window' href='./js1_2/function/regexparg-1.js'>js1_2/function/regexparg-1.js</a> failed</b> <br> [ <a href='#failure8'>Previous Failure</a> | <a href='#failure10'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br> @@ -163,7 +163,7 @@ Testcase terminated with signal 0<br> Complete testcase output was:<br> BUGNUMBER: 10278<br> function-001.js functions not separated by semicolons are errors in version 120 and higher<br> -eval("function f(){}function g(){}") = undefined FAILED! expected: error<br> +eval("function f(){}function g(){}") = undefined PASSED!<br> </tt><br> <a name='failure19'></a><dd><b>Testcase <a target='other_window' href='./js1_3/Script/script-001.js'>js1_3/Script/script-001.js</a> failed</b> <br> [ <a href='#failure18'>Previous Failure</a> | <a href='#failure20'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br> @@ -181,7 +181,7 @@ Testcase terminated with signal 0<br> Complete testcase output was:<br> BUGNUMBER: 10278<br> function-001.js functions not separated by semicolons are errors in version 120 and higher<br> -eval("function f(){}function g(){}") = undefined FAILED! expected: error<br> +eval("function f(){}function g(){}") = undefined PASSED!<br> </tt><br> <a name='failure21'></a><dd><b>Testcase <a target='other_window' href='./js1_5/Exceptions/catchguard-001.js'>js1_5/Exceptions/catchguard-001.js</a> failed</b> <br> [ <a href='#failure20'>Previous Failure</a> | <a href='#failure22'>Next Failure</a> | <a href='#tippy_top'>Top of Page</a> ]<br> @@ -437,7 +437,7 @@ global code@./js1_6/String/regress-306591.js:48<br> <pre> <a name='retest_list'></a> <h2>Retest List</h2><br> -# Retest List, squirrelfish, generated Thu Sep 6 15:11:19 2012. +# Retest List, squirrelfish, generated Fri Sep 21 18:29:47 2012. # Original test base was: All tests. # 1116 of 1124 test(s) were completed, 44 failures reported. ecma_2/Exceptions/function-001.js diff --git a/Source/JavaScriptCore/tests/mozilla/js1_2/function/function-001-n.js b/Source/JavaScriptCore/tests/mozilla/js1_2/function/function-001-n.js index 5ae01a956..99e044229 100644 --- a/Source/JavaScriptCore/tests/mozilla/js1_2/function/function-001-n.js +++ b/Source/JavaScriptCore/tests/mozilla/js1_2/function/function-001-n.js @@ -53,7 +53,7 @@ testcases[tc++] = new TestCase( SECTION, "eval(\"function f(){}function g(){}\")", - "error", + undefined, eval("function f(){}function g(){}") ); test(); diff --git a/Source/JavaScriptCore/tests/mozilla/js1_3/Script/function-001-n.js b/Source/JavaScriptCore/tests/mozilla/js1_3/Script/function-001-n.js index 5b4add048..7d42ce217 100644 --- a/Source/JavaScriptCore/tests/mozilla/js1_3/Script/function-001-n.js +++ b/Source/JavaScriptCore/tests/mozilla/js1_3/Script/function-001-n.js @@ -53,7 +53,7 @@ testcases[tc++] = new TestCase( SECTION, "eval(\"function f(){}function g(){}\")", - "error", + undefined, eval("function f(){}function g(){}") ); test(); diff --git a/Source/JavaScriptCore/tests/mozilla/js1_3/regress/function-001-n.js b/Source/JavaScriptCore/tests/mozilla/js1_3/regress/function-001-n.js index 5b4add048..7d42ce217 100644 --- a/Source/JavaScriptCore/tests/mozilla/js1_3/regress/function-001-n.js +++ b/Source/JavaScriptCore/tests/mozilla/js1_3/regress/function-001-n.js @@ -53,7 +53,7 @@ testcases[tc++] = new TestCase( SECTION, "eval(\"function f(){}function g(){}\")", - "error", + undefined, eval("function f(){}function g(){}") ); test(); |