diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-24 16:36:50 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-24 16:36:50 +0100 |
commit | ad0d549d4cc13433f77c1ac8f0ab379c83d93f28 (patch) | |
tree | b34b0daceb7c8e7fdde4b4ec43650ab7caadb0a9 /Source/JavaScriptCore/runtime | |
parent | 03e12282df9aa1e1fb05a8b90f1cfc2e08764cec (diff) | |
download | qtwebkit-ad0d549d4cc13433f77c1ac8f0ab379c83d93f28.tar.gz |
Imported WebKit commit bb52bf3c0119e8a128cd93afe5572413a8617de9 (http://svn.webkit.org/repository/webkit/trunk@108790)
Diffstat (limited to 'Source/JavaScriptCore/runtime')
50 files changed, 881 insertions, 317 deletions
diff --git a/Source/JavaScriptCore/runtime/Arguments.cpp b/Source/JavaScriptCore/runtime/Arguments.cpp index 6a675ab84..a099adb75 100644 --- a/Source/JavaScriptCore/runtime/Arguments.cpp +++ b/Source/JavaScriptCore/runtime/Arguments.cpp @@ -243,6 +243,9 @@ bool Arguments::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i) { Arguments* thisObject = jsCast<Arguments*>(cell); if (i < thisObject->d->numArguments) { + if (!Base::deletePropertyByIndex(cell, exec, i)) + return false; + if (!thisObject->d->deletedArguments) { thisObject->d->deletedArguments = adoptArrayPtr(new bool[thisObject->d->numArguments]); memset(thisObject->d->deletedArguments.get(), 0, sizeof(bool) * thisObject->d->numArguments); @@ -258,10 +261,16 @@ bool Arguments::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i) bool Arguments::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& propertyName) { + if (exec->globalData().isInDefineOwnProperty()) + return Base::deleteProperty(cell, exec, propertyName); + Arguments* thisObject = jsCast<Arguments*>(cell); bool isArrayIndex; unsigned i = propertyName.toArrayIndex(isArrayIndex); if (isArrayIndex && i < thisObject->d->numArguments) { + if (!Base::deleteProperty(cell, exec, propertyName)) + return false; + if (!thisObject->d->deletedArguments) { thisObject->d->deletedArguments = adoptArrayPtr(new bool[thisObject->d->numArguments]); memset(thisObject->d->deletedArguments.get(), 0, sizeof(bool) * thisObject->d->numArguments); @@ -285,12 +294,74 @@ bool Arguments::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& thisObject->createStrictModeCalleeIfNecessary(exec); } - if (propertyName == exec->propertyNames().caller && !thisObject->d->isStrictMode) + if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode) thisObject->createStrictModeCallerIfNecessary(exec); return JSObject::deleteProperty(thisObject, exec, propertyName); } +bool Arguments::defineOwnProperty(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool shouldThrow) +{ + Arguments* thisObject = jsCast<Arguments*>(object); + bool isArrayIndex; + unsigned i = propertyName.toArrayIndex(isArrayIndex); + if (isArrayIndex && i < thisObject->d->numArguments) { + if (!Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow)) + return false; + + if (!thisObject->d->deletedArguments) { + thisObject->d->deletedArguments = adoptArrayPtr(new bool[thisObject->d->numArguments]); + memset(thisObject->d->deletedArguments.get(), 0, sizeof(bool) * thisObject->d->numArguments); + } + // From ES 5.1, 10.6 Arguments Object + // 5. If the value of isMapped is not undefined, then + if (!thisObject->d->deletedArguments[i]) { + // a. If IsAccessorDescriptor(Desc) is true, then + if (descriptor.isAccessorDescriptor()) { + // i. Call the [[Delete]] internal method of map passing P, and false as the arguments. + thisObject->d->deletedArguments[i] = true; + } else if (descriptor.value()) { // b. Else i. If Desc.[[Value]] is present, then + // 1. Call the [[Put]] internal method of map passing P, Desc.[[Value]], and Throw as the arguments. + // ii. If Desc.[[Writable]] is present and its value is false, then + thisObject->argument(i).set(exec->globalData(), thisObject, descriptor.value()); + if (descriptor.writablePresent() && !descriptor.writable()) + thisObject->d->deletedArguments[i] = true; // 1. Call the [[Delete]] internal method of map passing P and false as arguments. + } + } + + return true; + } + + if (propertyName == exec->propertyNames().length && !thisObject->d->overrodeLength) { + thisObject->d->overrodeLength = true; + if (!descriptor.isAccessorDescriptor()) { + if (!descriptor.value()) + descriptor.setValue(jsNumber(thisObject->d->numArguments)); + if (!descriptor.configurablePresent()) + descriptor.setConfigurable(true); + } + if (!descriptor.configurablePresent()) + descriptor.setConfigurable(true); + } + + if (propertyName == exec->propertyNames().callee && !thisObject->d->overrodeCallee) { + thisObject->d->overrodeCallee = true; + if (!descriptor.isAccessorDescriptor()) { + if (!descriptor.value()) + descriptor.setValue(thisObject->d->callee.get()); + if (!descriptor.configurablePresent()) + descriptor.setConfigurable(true); + } + if (!descriptor.configurablePresent()) + descriptor.setConfigurable(true); + } + + if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode) + thisObject->createStrictModeCallerIfNecessary(exec); + + return Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow); +} + void Arguments::tearOff(CallFrame* callFrame) { if (isTornOff()) diff --git a/Source/JavaScriptCore/runtime/Arguments.h b/Source/JavaScriptCore/runtime/Arguments.h index 3564fe447..ee54a49eb 100644 --- a/Source/JavaScriptCore/runtime/Arguments.h +++ b/Source/JavaScriptCore/runtime/Arguments.h @@ -117,6 +117,7 @@ namespace JSC { static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue); static bool deleteProperty(JSCell*, ExecState*, const Identifier& propertyName); static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); + static bool defineOwnProperty(JSObject*, ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow); void createStrictModeCallerIfNecessary(ExecState*); void createStrictModeCalleeIfNecessary(ExecState*); diff --git a/Source/JavaScriptCore/runtime/CodeSpecializationKind.h b/Source/JavaScriptCore/runtime/CodeSpecializationKind.h new file mode 100644 index 000000000..ba2a54f37 --- /dev/null +++ b/Source/JavaScriptCore/runtime/CodeSpecializationKind.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CodeSpecializationKind_h +#define CodeSpecializationKind_h + +namespace JSC { + +enum CodeSpecializationKind { CodeForCall, CodeForConstruct }; + +} // namespace JSC + +#endif // CodeSpecializationKind_h + diff --git a/Source/JavaScriptCore/runtime/CommonIdentifiers.h b/Source/JavaScriptCore/runtime/CommonIdentifiers.h index 08d8644b5..d79e5c783 100644 --- a/Source/JavaScriptCore/runtime/CommonIdentifiers.h +++ b/Source/JavaScriptCore/runtime/CommonIdentifiers.h @@ -62,6 +62,7 @@ macro(prototype) \ macro(set) \ macro(source) \ + macro(stack) \ macro(test) \ macro(toExponential) \ macro(toFixed) \ diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.h b/Source/JavaScriptCore/runtime/CommonSlowPaths.h index 86c4bd5c2..345af2ebe 100644 --- a/Source/JavaScriptCore/runtime/CommonSlowPaths.h +++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.h @@ -27,6 +27,7 @@ #define CommonSlowPaths_h #include "CodeBlock.h" +#include "CodeSpecializationKind.h" #include "ExceptionHelpers.h" #include "JSArray.h" @@ -41,6 +42,38 @@ namespace JSC { namespace CommonSlowPaths { +ALWAYS_INLINE ExecState* arityCheckFor(ExecState* exec, RegisterFile* registerFile, CodeSpecializationKind kind) +{ + JSFunction* callee = asFunction(exec->callee()); + ASSERT(!callee->isHostFunction()); + CodeBlock* newCodeBlock = &callee->jsExecutable()->generatedBytecodeFor(kind); + int argumentCountIncludingThis = exec->argumentCountIncludingThis(); + + // This ensures enough space for the worst case scenario of zero arguments passed by the caller. + if (!registerFile->grow(exec->registers() + newCodeBlock->numParameters() + newCodeBlock->m_numCalleeRegisters)) + return 0; + + ASSERT(argumentCountIncludingThis < newCodeBlock->numParameters()); + + // Too few arguments -- copy call frame and arguments, then fill in missing arguments with undefined. + size_t delta = newCodeBlock->numParameters() - argumentCountIncludingThis; + Register* src = exec->registers(); + Register* dst = exec->registers() + delta; + + int i; + int end = -ExecState::offsetFor(argumentCountIncludingThis); + for (i = -1; i >= end; --i) + dst[i] = src[i]; + + end -= delta; + for ( ; i >= end; --i) + dst[i] = jsUndefined(); + + ExecState* newExec = ExecState::create(dst); + ASSERT((void*)newExec <= registerFile->end()); + return newExec; +} + ALWAYS_INLINE bool opInstanceOfSlow(ExecState* exec, JSValue value, JSValue baseVal, JSValue proto) { ASSERT(!value.isCell() || !baseVal.isCell() || !proto.isCell() diff --git a/Source/JavaScriptCore/runtime/DatePrototype.cpp b/Source/JavaScriptCore/runtime/DatePrototype.cpp index 922fb0a86..ddea33786 100644 --- a/Source/JavaScriptCore/runtime/DatePrototype.cpp +++ b/Source/JavaScriptCore/runtime/DatePrototype.cpp @@ -60,7 +60,7 @@ #include <sys/timeb.h> #endif -#if PLATFORM(MAC) || PLATFORM(IOS) || PLATFORM(WX) || (PLATFORM(QT) && OS(DARWIN)) +#if PLATFORM(MAC) || PLATFORM(IOS) || (PLATFORM(WX) && OS(DARWIN)) || (PLATFORM(QT) && OS(DARWIN)) #include <CoreFoundation/CoreFoundation.h> #elif USE(ICU_UNICODE) #include <unicode/udat.h> @@ -130,7 +130,7 @@ namespace JSC { enum LocaleDateTimeFormat { LocaleDateAndTime, LocaleDate, LocaleTime }; -#if PLATFORM(MAC) || PLATFORM(IOS) || PLATFORM(WX) || (PLATFORM(QT) && OS(DARWIN)) +#if PLATFORM(MAC) || PLATFORM(IOS) || (PLATFORM(WX) && OS(DARWIN)) || (PLATFORM(QT) && OS(DARWIN)) // FIXME: Since this is superior to the strftime-based version, why limit this to PLATFORM(MAC)? // Instead we should consider using this whenever USE(CF) is true. diff --git a/Source/JavaScriptCore/runtime/Error.cpp b/Source/JavaScriptCore/runtime/Error.cpp index 0947e3c20..243dc8856 100644 --- a/Source/JavaScriptCore/runtime/Error.cpp +++ b/Source/JavaScriptCore/runtime/Error.cpp @@ -26,7 +26,9 @@ #include "ConstructData.h" #include "ErrorConstructor.h" +#include "ExceptionHelpers.h" #include "FunctionPrototype.h" +#include "JSArray.h" #include "JSFunction.h" #include "JSGlobalObject.h" #include "JSObject.h" @@ -116,7 +118,7 @@ JSObject* createURIError(ExecState* exec, const UString& message) return createURIError(exec->lexicalGlobalObject(), message); } -JSObject* addErrorInfo(JSGlobalData* globalData, JSObject* error, int line, const SourceCode& source) +JSObject* addErrorInfo(JSGlobalData* globalData, JSObject* error, int line, const SourceCode& source, const Vector<StackFrame>& stackTrace) { const UString& sourceURL = source.provider()->url(); @@ -124,13 +126,34 @@ JSObject* addErrorInfo(JSGlobalData* globalData, JSObject* error, int line, cons error->putDirect(*globalData, Identifier(globalData, linePropertyName), jsNumber(line), ReadOnly | DontDelete); if (!sourceURL.isNull()) error->putDirect(*globalData, Identifier(globalData, sourceURLPropertyName), jsString(globalData, sourceURL), ReadOnly | DontDelete); + if (!stackTrace.isEmpty()) { + JSGlobalObject* globalObject = 0; + if (isTerminatedExecutionException(error) || isInterruptedExecutionException(error)) + globalObject = globalData->dynamicGlobalObject; + else + globalObject = error->globalObject(); + // We use the tryCreateUninitialized creation mechanism and related initialization + // functions as they're the only mechanism we currently have that will guarantee we + // don't call setters on the prototype. Technically it's faster than the alternative, + // but the numerous allocations that take place in this loop makes that last bit + // somewhat moot. + JSArray* stackTraceArray = JSArray::tryCreateUninitialized(*globalData, globalObject->arrayStructure(), stackTrace.size()); + if (!stackTraceArray) + return error; + for (unsigned i = 0; i < stackTrace.size(); i++) { + UString stackLevel = stackTrace[i].toString(globalObject->globalExec()); + stackTraceArray->initializeIndex(*globalData, i, jsString(globalData, stackLevel)); + } + stackTraceArray->completeInitialization(stackTrace.size()); + error->putDirect(*globalData, globalData->propertyNames->stack, stackTraceArray, ReadOnly | DontDelete); + } return error; } -JSObject* addErrorInfo(ExecState* exec, JSObject* error, int line, const SourceCode& source) +JSObject* addErrorInfo(ExecState* exec, JSObject* error, int line, const SourceCode& source, const Vector<StackFrame>& stackTrace) { - return addErrorInfo(&exec->globalData(), error, line, source); + return addErrorInfo(&exec->globalData(), error, line, source, stackTrace); } bool hasErrorInfo(ExecState* exec, JSObject* error) diff --git a/Source/JavaScriptCore/runtime/Error.h b/Source/JavaScriptCore/runtime/Error.h index 88b540a35..59b39495f 100644 --- a/Source/JavaScriptCore/runtime/Error.h +++ b/Source/JavaScriptCore/runtime/Error.h @@ -24,6 +24,7 @@ #define Error_h #include "InternalFunction.h" +#include "Interpreter.h" #include "JSObject.h" #include <stdint.h> @@ -56,9 +57,9 @@ namespace JSC { // Methods to add bool hasErrorInfo(ExecState*, JSObject* error); - JSObject* addErrorInfo(JSGlobalData*, JSObject* error, int line, const SourceCode&); + JSObject* addErrorInfo(JSGlobalData*, JSObject* error, int line, const SourceCode&, const Vector<StackFrame>&); // ExecState wrappers. - JSObject* addErrorInfo(ExecState*, JSObject* error, int line, const SourceCode&); + JSObject* addErrorInfo(ExecState*, JSObject* error, int line, const SourceCode&, const Vector<StackFrame>&); // Methods to throw Errors. JS_EXPORT_PRIVATE JSValue throwError(ExecState*, JSValue); diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp index bf49767ab..25ddf764a 100644 --- a/Source/JavaScriptCore/runtime/Executable.cpp +++ b/Source/JavaScriptCore/runtime/Executable.cpp @@ -29,6 +29,7 @@ #include "BytecodeGenerator.h" #include "CodeBlock.h" #include "DFGDriver.h" +#include "ExecutionHarness.h" #include "JIT.h" #include "JITDriver.h" #include "Parser.h" @@ -39,10 +40,12 @@ namespace JSC { const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, 0, CREATE_METHOD_TABLE(ExecutableBase) }; +#if ENABLE(JIT) void ExecutableBase::destroy(JSCell* cell) { jsCast<ExecutableBase*>(cell)->ExecutableBase::~ExecutableBase(); } +#endif inline void ExecutableBase::clearCode() { @@ -67,10 +70,12 @@ Intrinsic ExecutableBase::intrinsic() const const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(NativeExecutable) }; +#if ENABLE(JIT) void NativeExecutable::destroy(JSCell* cell) { jsCast<NativeExecutable*>(cell)->NativeExecutable::~NativeExecutable(); } +#endif #if ENABLE(DFG_JIT) Intrinsic NativeExecutable::intrinsic() const @@ -84,7 +89,7 @@ Intrinsic NativeExecutable::intrinsic() const template<typename T> static void jettisonCodeBlock(JSGlobalData& globalData, OwnPtr<T>& codeBlock) { - ASSERT(codeBlock->getJITType() != JITCode::BaselineJIT); + ASSERT(JITCode::isOptimizingJIT(codeBlock->getJITType())); ASSERT(codeBlock->alternative()); OwnPtr<T> codeBlockToJettison = codeBlock.release(); codeBlock = static_pointer_cast<T>(codeBlockToJettison->releaseAlternative()); @@ -100,10 +105,12 @@ void NativeExecutable::finalize(JSCell* cell) const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(ScriptExecutable) }; +#if ENABLE(JIT) void ScriptExecutable::destroy(JSCell* cell) { jsCast<ScriptExecutable*>(cell)->ScriptExecutable::~ScriptExecutable(); } +#endif const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(EvalExecutable) }; @@ -169,9 +176,32 @@ JSObject* EvalExecutable::compileOptimized(ExecState* exec, ScopeChainNode* scop return error; } +#if ENABLE(JIT) +void EvalExecutable::jitCompile(JSGlobalData& globalData) +{ + bool result = jitCompileIfAppropriate(globalData, m_evalCodeBlock, m_jitCodeForCall, JITCode::bottomTierJIT()); + ASSERT_UNUSED(result, result); +} +#endif + +inline const char* samplingDescription(JITCode::JITType jitType) +{ + switch (jitType) { + case JITCode::InterpreterThunk: + return "Interpreter Compilation (TOTAL)"; + case JITCode::BaselineJIT: + return "Baseline Compilation (TOTAL)"; + case JITCode::DFGJIT: + return "DFG Compilation (TOTAL)"; + default: + ASSERT_NOT_REACHED(); + return 0; + } +} + JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType) { - SamplingRegion samplingRegion(jitType == JITCode::BaselineJIT ? "Baseline Compilation (TOTAL)" : "DFG Compilation (TOTAL)"); + SamplingRegion samplingRegion(samplingDescription(jitType)); #if !ENABLE(JIT) UNUSED_PARAM(jitType); @@ -212,12 +242,12 @@ JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scope } #if ENABLE(JIT) - if (!jitCompileIfAppropriate(*globalData, m_evalCodeBlock, m_jitCodeForCall, jitType)) + if (!prepareForExecution(*globalData, m_evalCodeBlock, m_jitCodeForCall, jitType)) return 0; #endif #if ENABLE(JIT) -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) if (!m_jitCodeForCall) Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_evalCodeBlock)); else @@ -297,9 +327,17 @@ JSObject* ProgramExecutable::compileOptimized(ExecState* exec, ScopeChainNode* s return error; } +#if ENABLE(JIT) +void ProgramExecutable::jitCompile(JSGlobalData& globalData) +{ + bool result = jitCompileIfAppropriate(globalData, m_programCodeBlock, m_jitCodeForCall, JITCode::bottomTierJIT()); + ASSERT_UNUSED(result, result); +} +#endif + JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType) { - SamplingRegion samplingRegion(jitType == JITCode::BaselineJIT ? "Baseline Compilation (TOTAL)" : "DFG Compilation (TOTAL)"); + SamplingRegion samplingRegion(samplingDescription(jitType)); #if !ENABLE(JIT) UNUSED_PARAM(jitType); @@ -338,12 +376,12 @@ JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* sc } #if ENABLE(JIT) - if (!jitCompileIfAppropriate(*globalData, m_programCodeBlock, m_jitCodeForCall, jitType)) + if (!prepareForExecution(*globalData, m_programCodeBlock, m_jitCodeForCall, jitType)) return 0; #endif #if ENABLE(JIT) -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) if (!m_jitCodeForCall) Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_programCodeBlock)); else @@ -414,7 +452,7 @@ FunctionCodeBlock* FunctionExecutable::baselineCodeBlockFor(CodeSpecializationKi while (result->alternative()) result = static_cast<FunctionCodeBlock*>(result->alternative()); ASSERT(result); - ASSERT(result->getJITType() == JITCode::BaselineJIT); + ASSERT(JITCode::isBaselineCode(result->getJITType())); return result; } @@ -440,6 +478,20 @@ JSObject* FunctionExecutable::compileOptimizedForConstruct(ExecState* exec, Scop return error; } +#if ENABLE(JIT) +void FunctionExecutable::jitCompileForCall(JSGlobalData& globalData) +{ + bool result = jitCompileFunctionIfAppropriate(globalData, m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, m_symbolTable, JITCode::bottomTierJIT()); + ASSERT_UNUSED(result, result); +} + +void FunctionExecutable::jitCompileForConstruct(JSGlobalData& globalData) +{ + bool result = jitCompileFunctionIfAppropriate(globalData, m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, m_symbolTable, JITCode::bottomTierJIT()); + ASSERT_UNUSED(result, result); +} +#endif + FunctionCodeBlock* FunctionExecutable::codeBlockWithBytecodeFor(CodeSpecializationKind kind) { FunctionCodeBlock* codeBlock = baselineCodeBlockFor(kind); @@ -484,7 +536,7 @@ PassOwnPtr<FunctionCodeBlock> FunctionExecutable::produceCodeBlockFor(ScopeChain JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType) { - SamplingRegion samplingRegion(jitType == JITCode::BaselineJIT ? "Baseline Compilation (TOTAL)" : "DFG Compilation (TOTAL)"); + SamplingRegion samplingRegion(samplingDescription(jitType)); #if !ENABLE(JIT) UNUSED_PARAM(exec); @@ -506,12 +558,12 @@ JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChain m_symbolTable = m_codeBlockForCall->sharedSymbolTable(); #if ENABLE(JIT) - if (!jitCompileFunctionIfAppropriate(exec->globalData(), m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, m_symbolTable, jitType)) + if (!prepareFunctionForExecution(exec->globalData(), m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, m_symbolTable, jitType, CodeForCall)) return 0; #endif #if ENABLE(JIT) -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) if (!m_jitCodeForCall) Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall)); else @@ -526,7 +578,7 @@ JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChain JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType) { - SamplingRegion samplingRegion(jitType == JITCode::BaselineJIT ? "Baseline Compilation (TOTAL)" : "DFG Compilation (TOTAL)"); + SamplingRegion samplingRegion(samplingDescription(jitType)); #if !ENABLE(JIT) UNUSED_PARAM(jitType); @@ -548,12 +600,12 @@ JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, Scope m_symbolTable = m_codeBlockForConstruct->sharedSymbolTable(); #if ENABLE(JIT) - if (!jitCompileFunctionIfAppropriate(exec->globalData(), m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, m_symbolTable, jitType)) + if (!prepareFunctionForExecution(exec->globalData(), m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, m_symbolTable, jitType, CodeForConstruct)) return 0; #endif #if ENABLE(JIT) -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) if (!m_jitCodeForConstruct) Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForConstruct)); else diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h index 6800b5a82..69e80b28e 100644 --- a/Source/JavaScriptCore/runtime/Executable.h +++ b/Source/JavaScriptCore/runtime/Executable.h @@ -27,6 +27,7 @@ #define Executable_h #include "CallData.h" +#include "CodeSpecializationKind.h" #include "JSFunction.h" #include "Interpreter.h" #include "Nodes.h" @@ -39,12 +40,12 @@ namespace JSC { class Debugger; class EvalCodeBlock; class FunctionCodeBlock; + class LLIntOffsetsExtractor; class ProgramCodeBlock; class ScopeChainNode; struct ExceptionInfo; - enum CodeSpecializationKind { CodeForCall, CodeForConstruct }; enum CompilationKind { FirstCompilation, OptimizingCompilation }; inline bool isCall(CodeSpecializationKind kind) @@ -77,7 +78,9 @@ namespace JSC { public: typedef JSCell Base; +#if ENABLE(JIT) static void destroy(JSCell*); +#endif bool isHostFunction() const { @@ -197,7 +200,7 @@ namespace JSC { } #endif -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) static NativeExecutable* create(JSGlobalData& globalData, NativeFunction function, NativeFunction constructor) { ASSERT(!globalData.canUseJIT()); @@ -208,7 +211,9 @@ namespace JSC { } #endif +#if ENABLE(JIT) static void destroy(JSCell*); +#endif NativeFunction function() { return m_function; } NativeFunction constructor() { return m_constructor; } @@ -233,7 +238,7 @@ namespace JSC { } #endif -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) void finishCreation(JSGlobalData& globalData) { ASSERT(!globalData.canUseJIT()); @@ -276,7 +281,9 @@ namespace JSC { { } +#if ENABLE(JIT) static void destroy(JSCell*); +#endif const SourceCode& source() { return m_source; } intptr_t sourceID() const { return m_source.provider()->asID(); } @@ -319,6 +326,7 @@ namespace JSC { }; class EvalExecutable : public ScriptExecutable { + friend class LLIntOffsetsExtractor; public: typedef ScriptExecutable Base; @@ -338,6 +346,7 @@ namespace JSC { #if ENABLE(JIT) void jettisonOptimizedCode(JSGlobalData&); + void jitCompile(JSGlobalData&); #endif EvalCodeBlock& generatedBytecode() @@ -384,6 +393,7 @@ namespace JSC { }; class ProgramExecutable : public ScriptExecutable { + friend class LLIntOffsetsExtractor; public: typedef ScriptExecutable Base; @@ -411,6 +421,7 @@ namespace JSC { #if ENABLE(JIT) void jettisonOptimizedCode(JSGlobalData&); + void jitCompile(JSGlobalData&); #endif ProgramCodeBlock& generatedBytecode() @@ -453,6 +464,7 @@ namespace JSC { class FunctionExecutable : public ScriptExecutable { friend class JIT; + friend class LLIntOffsetsExtractor; public: typedef ScriptExecutable Base; @@ -508,6 +520,7 @@ namespace JSC { #if ENABLE(JIT) void jettisonOptimizedCodeForCall(JSGlobalData&); + void jitCompileForCall(JSGlobalData&); #endif bool isGeneratedForCall() const @@ -535,6 +548,7 @@ namespace JSC { #if ENABLE(JIT) void jettisonOptimizedCodeForConstruct(JSGlobalData&); + void jitCompileForConstruct(JSGlobalData&); #endif bool isGeneratedForConstruct() const @@ -582,6 +596,16 @@ namespace JSC { jettisonOptimizedCodeForConstruct(globalData); } } + + void jitCompileFor(JSGlobalData& globalData, CodeSpecializationKind kind) + { + if (kind == CodeForCall) { + jitCompileForCall(globalData); + return; + } + ASSERT(kind == CodeForConstruct); + jitCompileForConstruct(globalData); + } #endif bool isGeneratedFor(CodeSpecializationKind kind) diff --git a/Source/JavaScriptCore/runtime/ExecutionHarness.h b/Source/JavaScriptCore/runtime/ExecutionHarness.h new file mode 100644 index 000000000..774c5bf6b --- /dev/null +++ b/Source/JavaScriptCore/runtime/ExecutionHarness.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ExecutionHarness_h +#define ExecutionHarness_h + +#include <wtf/Platform.h> + +#if ENABLE(JIT) + +#include "JITDriver.h" +#include "LLIntEntrypoints.h" + +namespace JSC { + +template<typename CodeBlockType> +inline bool prepareForExecution(JSGlobalData& globalData, OwnPtr<CodeBlockType>& codeBlock, JITCode& jitCode, JITCode::JITType jitType) +{ +#if ENABLE(LLINT) + if (JITCode::isBaselineCode(jitType)) { + // Start off in the low level interpreter. + LLInt::getEntrypoint(globalData, codeBlock.get(), jitCode); + codeBlock->setJITCode(jitCode, MacroAssemblerCodePtr()); + return true; + } +#endif // ENABLE(LLINT) + return jitCompileIfAppropriate(globalData, codeBlock, jitCode, jitType); +} + +inline bool prepareFunctionForExecution(JSGlobalData& globalData, OwnPtr<FunctionCodeBlock>& codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck, SharedSymbolTable*& symbolTable, JITCode::JITType jitType, CodeSpecializationKind kind) +{ +#if ENABLE(LLINT) + if (JITCode::isBaselineCode(jitType)) { + // Start off in the low level interpreter. + LLInt::getFunctionEntrypoint(globalData, kind, jitCode, jitCodeWithArityCheck); + codeBlock->setJITCode(jitCode, jitCodeWithArityCheck); + return true; + } +#else + UNUSED_PARAM(kind); +#endif // ENABLE(LLINT) + return jitCompileFunctionIfAppropriate(globalData, codeBlock, jitCode, jitCodeWithArityCheck, symbolTable, jitType); +} + +} // namespace JSC + +#endif // ENABLE(JIT) + +#endif // ExecutionHarness_h + diff --git a/Source/JavaScriptCore/runtime/JSActivation.h b/Source/JavaScriptCore/runtime/JSActivation.h index c18492344..80c8aa8d0 100644 --- a/Source/JavaScriptCore/runtime/JSActivation.h +++ b/Source/JavaScriptCore/runtime/JSActivation.h @@ -75,6 +75,8 @@ namespace JSC { static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(globalData, globalObject, proto, TypeInfo(ActivationObjectType, StructureFlags), &s_info); } + bool isValidScopedLookup(int index) { return index < m_numCapturedVars; } + protected: void finishCreation(CallFrame*); static const unsigned StructureFlags = IsEnvironmentRecord | OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags; diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp index c84fb5b10..71d520018 100644 --- a/Source/JavaScriptCore/runtime/JSArray.cpp +++ b/Source/JavaScriptCore/runtime/JSArray.cpp @@ -24,8 +24,8 @@ #include "JSArray.h" #include "ArrayPrototype.h" -#include "BumpSpace.h" -#include "BumpSpaceInlineMethods.h" +#include "CopiedSpace.h" +#include "CopiedSpaceInlineMethods.h" #include "CachedCall.h" #include "Error.h" #include "Executable.h" @@ -42,6 +42,7 @@ using namespace WTF; namespace JSC { ASSERT_CLASS_FITS_IN_CELL(JSArray); +ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSArray); // Overview of JSArray // @@ -160,10 +161,6 @@ void JSArray::finishCreation(JSGlobalData& globalData, unsigned initialLength) m_storage->m_inCompactInitialization = false; #endif - WriteBarrier<Unknown>* vector = m_storage->m_vector; - for (size_t i = 0; i < initialVectorLength; ++i) - vector[i].clear(); - checkConsistency(); } @@ -193,10 +190,6 @@ JSArray* JSArray::tryFinishCreationUninitialized(JSGlobalData& globalData, unsig m_storage->m_inCompactInitialization = true; #endif - WriteBarrier<Unknown>* vector = m_storage->m_vector; - for (size_t i = initialLength; i < initialVectorLength; ++i) - vector[i].clear(); - return this; } @@ -222,7 +215,17 @@ inline std::pair<SparseArrayValueMap::iterator, bool> SparseArrayValueMap::add(J inline void SparseArrayValueMap::put(ExecState* exec, JSArray* array, unsigned i, JSValue value) { - SparseArrayEntry& entry = add(array, i).first->second; + std::pair<SparseArrayValueMap::iterator, bool> result = add(array, i); + SparseArrayEntry& entry = result.first->second; + + // To save a separate find & add, we first always add to the sparse map. + // In the uncommon case that this is a new property, and the array is not + // extensible, this is not the right thing to have done - so remove again. + if (result.second && !array->isExtensible()) { + remove(result.first); + // FIXME: should throw in strict mode. + return; + } if (!(entry.attributes & Accessor)) { if (entry.attributes & ReadOnly) { @@ -240,7 +243,8 @@ inline void SparseArrayValueMap::put(ExecState* exec, JSArray* array, unsigned i JSObject* setter = asGetterSetter(accessor)->setter(); if (!setter) { - throwTypeError(exec, "setting a property that has only a getter"); + // FIXME: should throw if being called from strict mode. + // throwTypeError(exec, "setting a property that has only a getter"); return; } @@ -383,7 +387,7 @@ void JSArray::putDescriptor(ExecState* exec, SparseArrayEntry* entryInMap, Prope accessor->setSetter(exec->globalData(), setter); entryInMap->set(exec->globalData(), this, accessor); - entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor) & ~DontDelete; + entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor) & ~ReadOnly; return; } @@ -464,7 +468,7 @@ bool JSArray::defineOwnNumericProperty(ExecState* exec, unsigned index, Property // 7. If the [[Configurable]] field of current is false then if (!current.configurable()) { // 7.a. Reject, if the [[Configurable]] field of Desc is true. - if (descriptor.configurablePresent() && !descriptor.configurable()) + if (descriptor.configurablePresent() && descriptor.configurable()) return reject(exec, throwException, "Attempting to change configurable attribute of unconfigurable property."); // 7.b. Reject, if the [[Enumerable]] field of Desc is present and the [[Enumerable]] fields of current and Desc are the Boolean negation of each other. if (descriptor.enumerablePresent() && current.enumerable() != descriptor.enumerable()) @@ -682,7 +686,7 @@ bool JSArray::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const { JSArray* thisObject = jsCast<JSArray*>(object); if (propertyName == exec->propertyNames().length) { - descriptor.setDescriptor(jsNumber(thisObject->length()), DontDelete | DontEnum); + descriptor.setDescriptor(jsNumber(thisObject->length()), thisObject->isLengthWritable() ? DontDelete | DontEnum : DontDelete | DontEnum | ReadOnly); return true; } @@ -784,6 +788,9 @@ NEVER_INLINE void JSArray::putByIndexBeyondVectorLength(ExecState* exec, unsigne // First, handle cases where we don't currently have a sparse map. if (LIKELY(!map)) { + // If the array is not extensible, we should have entered dictionary mode, and created the spare map. + ASSERT(isExtensible()); + // Update m_length if necessary. if (i >= storage->m_length) storage->m_length = i + 1; @@ -807,7 +814,7 @@ NEVER_INLINE void JSArray::putByIndexBeyondVectorLength(ExecState* exec, unsigne unsigned length = storage->m_length; if (i >= length) { // Prohibit growing the array if length is not writable. - if (map->lengthIsReadOnly()) { + if (map->lengthIsReadOnly() || !isExtensible()) { // FIXME: should throw in strict mode. return; } @@ -977,10 +984,6 @@ bool JSArray::increaseVectorLength(JSGlobalData& globalData, unsigned newLength) m_storage->m_allocBase = newStorage; ASSERT(m_storage->m_allocBase); - WriteBarrier<Unknown>* vector = storage->m_vector; - for (unsigned i = vectorLength; i < newVectorLength; ++i) - vector[i].clear(); - m_vectorLength = newVectorLength; return true; @@ -1000,10 +1003,8 @@ bool JSArray::increaseVectorLength(JSGlobalData& globalData, unsigned newLength) m_indexBias = newIndexBias; m_storage = reinterpret_cast_ptr<ArrayStorage*>(reinterpret_cast<WriteBarrier<Unknown>*>(newAllocBase) + m_indexBias); - // Copy the ArrayStorage header & current contents of the vector, clear the new post-capacity. + // Copy the ArrayStorage header & current contents of the vector. memmove(m_storage, storage, storageSize(vectorLength)); - for (unsigned i = vectorLength; i < m_vectorLength; ++i) - m_storage->m_vector[i].clear(); // Free the old allocation, update m_allocBase. m_storage->m_allocBase = newAllocBase; @@ -1086,13 +1087,6 @@ bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, unsigned count) if (newAllocBase != m_storage->m_allocBase) { // Free the old allocation, update m_allocBase. m_storage->m_allocBase = newAllocBase; - - // We need to clear any entries in the vector beyond length. We only need to - // do this if this was a new allocation, because if we're using an existing - // allocation the post-capacity will already be cleared, and in an existing - // allocation we can only beshrinking the amount of post capacity. - for (unsigned i = requiredVectorLength; i < m_vectorLength; ++i) - m_storage->m_vector[i].clear(); } return true; @@ -1169,7 +1163,6 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException JSValue JSArray::pop(ExecState* exec) { checkConsistency(); - ArrayStorage* storage = m_storage; unsigned length = storage->m_length; @@ -1179,47 +1172,32 @@ JSValue JSArray::pop(ExecState* exec) return jsUndefined(); } - --length; - - JSValue result; - - if (length < m_vectorLength) { - WriteBarrier<Unknown>& valueSlot = storage->m_vector[length]; + unsigned index = length - 1; + if (index < m_vectorLength) { + WriteBarrier<Unknown>& valueSlot = storage->m_vector[index]; if (valueSlot) { --storage->m_numValuesInVector; - result = valueSlot.get(); + JSValue element = valueSlot.get(); valueSlot.clear(); - } else - result = jsUndefined(); - } else { - result = jsUndefined(); - if (SparseArrayValueMap* map = m_sparseValueMap) { - SparseArrayValueMap::iterator it = map->find(length); - if (it != map->notFound()) { - unsigned attributes = it->second.attributes; - - result = it->second.get(exec, this); - if (exec->hadException()) - return jsUndefined(); - - if (attributes & DontDelete) { - throwError(exec, createTypeError(exec, "Unable to delete property.")); - checkConsistency(); - return result; - } - - map->remove(it); - if (map->isEmpty() && !map->sparseMode()) - deallocateSparseMap(); - } + + ASSERT(isLengthWritable()); + storage->m_length = index; + checkConsistency(); + return element; } } - storage->m_length = length; - + // Let element be the result of calling the [[Get]] internal method of O with argument indx. + JSValue element = get(exec, index); + if (exec->hadException()) + return jsUndefined(); + // Call the [[Delete]] internal method of O with arguments indx and true. + deletePropertyByIndex(this, exec, index); + // Call the [[Put]] internal method of O with arguments "length", indx, and true. + setLength(exec, index, true); + // Return element. checkConsistency(); - - return result; + return element; } // Push & putIndex are almost identical, with two small differences. diff --git a/Source/JavaScriptCore/runtime/JSArray.h b/Source/JavaScriptCore/runtime/JSArray.h index a3354c602..3bb4c6320 100644 --- a/Source/JavaScriptCore/runtime/JSArray.h +++ b/Source/JavaScriptCore/runtime/JSArray.h @@ -28,6 +28,7 @@ namespace JSC { class JSArray; + class LLIntOffsetsExtractor; struct SparseArrayEntry : public WriteBarrier<Unknown> { typedef WriteBarrier<Unknown> Base; @@ -116,12 +117,15 @@ namespace JSC { unsigned m_numValuesInVector; void* m_allocBase; // Pointer to base address returned by malloc(). Keeping this pointer does eliminate false positives from the leak detector. #if CHECK_ARRAY_CONSISTENCY - bool m_inCompactInitialization; + uintptr_t m_inCompactInitialization; // Needs to be a uintptr_t for alignment purposes. +#else + uintptr_t m_padding; #endif WriteBarrier<Unknown> m_vector[1]; }; class JSArray : public JSNonFinalObject { + friend class LLIntOffsetsExtractor; friend class Walker; protected: @@ -135,23 +139,14 @@ namespace JSC { static void finalize(JSCell*); - static JSArray* create(JSGlobalData& globalData, Structure* structure, unsigned initialLength = 0) - { - JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure); - array->finishCreation(globalData, initialLength); - return array; - } + static JSArray* create(JSGlobalData&, Structure*, unsigned initialLength = 0); // tryCreateUninitialized is used for fast construction of arrays whose size and // 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& globalData, Structure* structure, unsigned initialLength) - { - JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure); - return array->tryFinishCreationUninitialized(globalData, initialLength); - } + static JSArray* tryCreateUninitialized(JSGlobalData&, Structure*, unsigned initialLength); JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&, bool throwException); @@ -253,6 +248,8 @@ namespace JSC { JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); + void enterDictionaryMode(JSGlobalData&); + protected: static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags; static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); @@ -274,7 +271,6 @@ namespace JSC { void setLengthWritable(ExecState*, bool writable); void putDescriptor(ExecState*, SparseArrayEntry*, PropertyDescriptor&, PropertyDescriptor& old); bool defineOwnNumericProperty(ExecState*, unsigned, PropertyDescriptor&, bool throwException); - void enterDictionaryMode(JSGlobalData&); void allocateSparseMap(JSGlobalData&); void deallocateSparseMap(); @@ -299,6 +295,19 @@ namespace JSC { void* m_subclassData; // A JSArray subclass can use this to fill the vector lazily. }; + inline JSArray* JSArray::create(JSGlobalData& globalData, Structure* structure, unsigned initialLength) + { + JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure); + array->finishCreation(globalData, initialLength); + return array; + } + + inline JSArray* JSArray::tryCreateUninitialized(JSGlobalData& globalData, Structure* structure, unsigned initialLength) + { + JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure); + return array->tryFinishCreationUninitialized(globalData, initialLength); + } + JSArray* asArray(JSValue); inline JSArray* asArray(JSCell* cell) diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h index 74833d12f..78d2d0801 100644 --- a/Source/JavaScriptCore/runtime/JSCell.h +++ b/Source/JavaScriptCore/runtime/JSCell.h @@ -36,9 +36,10 @@ namespace JSC { class JSGlobalObject; - class Structure; + class LLIntOffsetsExtractor; class PropertyDescriptor; class PropertyNameArray; + class Structure; enum EnumerationMode { ExcludeDontEnumProperties, @@ -61,6 +62,7 @@ namespace JSC { class JSCell { friend class JSValue; friend class MarkedBlock; + template<typename T> friend void* allocateCell(Heap&); public: enum CreatingEarlyCellTag { CreatingEarlyCell }; @@ -162,6 +164,8 @@ namespace JSC { static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&); private: + friend class LLIntOffsetsExtractor; + const ClassInfo* m_classInfo; WriteBarrier<Structure> m_structure; }; @@ -307,14 +311,34 @@ namespace JSC { return isCell() ? asCell()->toObject(exec, globalObject) : toObjectSlowCase(exec, globalObject); } - template <typename T> void* allocateCell(Heap& heap) +#if COMPILER(CLANG) + template<class T> + struct NeedsDestructor { + static const bool value = !__has_trivial_destructor(T); + }; +#else + // Write manual specializations for this struct template if you care about non-clang compilers. + template<class T> + struct NeedsDestructor { + static const bool value = true; + }; +#endif + + template<typename T> + void* allocateCell(Heap& heap) { #if ENABLE(GC_VALIDATION) ASSERT(sizeof(T) == T::s_info.cellSize); ASSERT(!heap.globalData()->isInitializingObject()); heap.globalData()->setInitializingObject(true); #endif - JSCell* result = static_cast<JSCell*>(heap.allocate(sizeof(T))); + JSCell* result = 0; + if (NeedsDestructor<T>::value) + result = static_cast<JSCell*>(heap.allocateWithDestructor(sizeof(T))); + else { + ASSERT(T::s_info.methodTable.destroy == JSCell::destroy); + result = static_cast<JSCell*>(heap.allocateWithoutDestructor(sizeof(T))); + } result->clearStructure(); return result; } diff --git a/Source/JavaScriptCore/runtime/JSFunction.cpp b/Source/JavaScriptCore/runtime/JSFunction.cpp index 72e1ce14f..253128279 100644 --- a/Source/JavaScriptCore/runtime/JSFunction.cpp +++ b/Source/JavaScriptCore/runtime/JSFunction.cpp @@ -50,6 +50,7 @@ EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState* exec) } ASSERT_CLASS_FITS_IN_CELL(JSFunction); +ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSFunction); const ClassInfo JSFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSFunction) }; @@ -108,13 +109,6 @@ void JSFunction::finishCreation(ExecState* exec, FunctionExecutable* executable, putDirectOffset(exec->globalData(), scopeChainNode->globalObject->functionNameOffset(), executable->nameValue()); } -void JSFunction::destroy(JSCell* cell) -{ - JSFunction* thisObject = jsCast<JSFunction*>(cell); - ASSERT(thisObject->classInfo()->isSubClassOf(&JSFunction::s_info)); - thisObject->JSFunction::~JSFunction(); -} - const UString& JSFunction::name(ExecState* exec) { return asString(getDirect(exec->globalData(), exec->globalData().propertyNames->name))->tryGetValue(); diff --git a/Source/JavaScriptCore/runtime/JSFunction.h b/Source/JavaScriptCore/runtime/JSFunction.h index a12b079d7..6e8557f59 100644 --- a/Source/JavaScriptCore/runtime/JSFunction.h +++ b/Source/JavaScriptCore/runtime/JSFunction.h @@ -33,6 +33,7 @@ namespace JSC { class FunctionPrototype; class JSActivation; class JSGlobalObject; + class LLIntOffsetsExtractor; class NativeExecutable; class SourceCode; namespace DFG { @@ -64,8 +65,6 @@ namespace JSC { return function; } - static void destroy(JSCell*); - JS_EXPORT_PRIVATE const UString& name(ExecState*); JS_EXPORT_PRIVATE const UString displayName(ExecState*); const UString calculatedDisplayName(ExecState*); @@ -142,6 +141,8 @@ namespace JSC { static void visitChildren(JSCell*, SlotVisitor&); private: + friend class LLIntOffsetsExtractor; + JS_EXPORT_PRIVATE bool isHostFunctionNonInline() const; static JSValue argumentsGetter(ExecState*, JSValue, const Identifier&); diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.cpp b/Source/JavaScriptCore/runtime/JSGlobalData.cpp index bbe520a1e..2bdc28ab7 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalData.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalData.cpp @@ -35,6 +35,7 @@ #include "DebuggerActivation.h" #include "FunctionConstructor.h" #include "GetterSetter.h" +#include "HostCallReturnValue.h" #include "Interpreter.h" #include "JSActivation.h" #include "JSAPIValueWrapper.h" @@ -141,6 +142,8 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread , keywords(adoptPtr(new Keywords(this))) , interpreter(0) , heap(this, heapSize) + , jsArrayClassInfo(&JSArray::s_info) + , jsFinalObjectClassInfo(&JSFinalObject::s_info) #if ENABLE(DFG_JIT) , sizeOfLastScratchBuffer(0) #endif @@ -160,6 +163,7 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread #if ENABLE(GC_VALIDATION) , m_isInitializingObject(false) #endif + , m_inDefineOwnProperty(false) { interpreter = new Interpreter; @@ -189,7 +193,7 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable); -#if ENABLE(JIT) && ENABLE(INTERPRETER) +#if ENABLE(JIT) && ENABLE(CLASSIC_INTERPRETER) #if USE(CF) CFStringRef canUseJITKey = CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman); CFBooleanRef canUseJIT = (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication); @@ -209,16 +213,20 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread #endif #endif #if ENABLE(JIT) -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) if (m_canUseJIT) m_canUseJIT = executableAllocator.isValid(); #endif jitStubs = adoptPtr(new JITThunks(this)); #endif - interpreter->initialize(this->canUseJIT()); + interpreter->initialize(&llintData, this->canUseJIT()); + + initializeHostCallReturnValue(); // This is needed to convince the linker not to drop host call return support. heap.notifyIsSafeToCollect(); + + llintData.performAssertions(*this); } void JSGlobalData::clearBuiltinStructures() @@ -383,7 +391,7 @@ static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic) NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, NativeFunction constructor) { -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) if (!canUseJIT()) return NativeExecutable::create(*this, function, constructor); #endif @@ -502,17 +510,17 @@ void JSGlobalData::dumpRegExpTrace() RTTraceList::iterator iter = ++m_rtTraceList->begin(); if (iter != m_rtTraceList->end()) { - printf("\nRegExp Tracing\n"); - printf(" match() matches\n"); - printf("Regular Expression JIT Address calls found\n"); - printf("----------------------------------------+----------------+----------+----------\n"); + dataLog("\nRegExp Tracing\n"); + dataLog(" match() matches\n"); + dataLog("Regular Expression JIT Address calls found\n"); + dataLog("----------------------------------------+----------------+----------+----------\n"); unsigned reCount = 0; for (; iter != m_rtTraceList->end(); ++iter, ++reCount) (*iter)->printTraceData(); - printf("%d Regular Expressions\n", reCount); + dataLog("%d Regular Expressions\n", reCount); } m_rtTraceList->clear(); diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.h b/Source/JavaScriptCore/runtime/JSGlobalData.h index 92817f2a2..7e54c00db 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalData.h +++ b/Source/JavaScriptCore/runtime/JSGlobalData.h @@ -30,15 +30,16 @@ #define JSGlobalData_h #include "CachedTranscendentalFunction.h" -#include "Intrinsic.h" #include "DateInstanceCache.h" #include "ExecutableAllocator.h" #include "Heap.h" -#include "Strong.h" +#include "Intrinsic.h" #include "JITStubs.h" #include "JSValue.h" +#include "LLIntData.h" #include "NumericStrings.h" #include "SmallStrings.h" +#include "Strong.h" #include "Terminator.h" #include "TimeoutChecker.h" #include "WeakRandom.h" @@ -65,6 +66,7 @@ namespace JSC { class JSGlobalObject; class JSObject; class Keywords; + class LLIntOffsetsExtractor; class NativeExecutable; class ParserArena; class RegExpCache; @@ -211,13 +213,23 @@ namespace JSC { codeBlocksBeingCompiled.removeLast(); } + void setInDefineOwnProperty(bool inDefineOwnProperty) + { + m_inDefineOwnProperty = inDefineOwnProperty; + } + + bool isInDefineOwnProperty() + { + return m_inDefineOwnProperty; + } + #if ENABLE(ASSEMBLER) ExecutableAllocator executableAllocator; #endif #if !ENABLE(JIT) bool canUseJIT() { return false; } // interpreter only -#elif !ENABLE(INTERPRETER) +#elif !ENABLE(CLASSIC_INTERPRETER) bool canUseJIT() { return true; } // jit only #else bool canUseJIT() { return m_canUseJIT; } @@ -241,7 +253,12 @@ namespace JSC { Heap heap; JSValue exception; -#if ENABLE(JIT) + + const ClassInfo* const jsArrayClassInfo; + const ClassInfo* const jsFinalObjectClassInfo; + + LLInt::Data llintData; + ReturnAddressPtr exceptionLocation; JSValue hostCallReturnValue; CallFrame* callFrameForThrow; @@ -271,7 +288,6 @@ namespace JSC { return scratchBuffers.last(); } #endif -#endif HashMap<OpaqueJSClass*, OwnPtr<OpaqueJSClassContextData> > opaqueJSClassData; @@ -332,7 +348,7 @@ namespace JSC { ASSERT(!m_##type##ArrayDescriptor.m_classInfo || m_##type##ArrayDescriptor.m_classInfo == descriptor.m_classInfo); \ m_##type##ArrayDescriptor = descriptor; \ } \ - const TypedArrayDescriptor& type##ArrayDescriptor() const { return m_##type##ArrayDescriptor; } + const TypedArrayDescriptor& type##ArrayDescriptor() const { ASSERT(m_##type##ArrayDescriptor.m_classInfo); return m_##type##ArrayDescriptor; } registerTypedArrayFunction(int8, Int8); registerTypedArrayFunction(int16, Int16); @@ -346,15 +362,19 @@ namespace JSC { #undef registerTypedArrayFunction private: + friend class LLIntOffsetsExtractor; + JSGlobalData(GlobalDataType, ThreadStackType, HeapSize); static JSGlobalData*& sharedInstanceInternal(); void createNativeThunk(); -#if ENABLE(JIT) && ENABLE(INTERPRETER) +#if ENABLE(JIT) && ENABLE(CLASSIC_INTERPRETER) bool m_canUseJIT; #endif #if ENABLE(GC_VALIDATION) bool m_isInitializingObject; #endif + bool m_inDefineOwnProperty; + TypedArrayDescriptor m_int8ArrayDescriptor; TypedArrayDescriptor m_int16ArrayDescriptor; TypedArrayDescriptor m_int32ArrayDescriptor; diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp index e648fbe21..8d3975848 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -78,7 +78,7 @@ namespace JSC { const ClassInfo JSGlobalObject::s_info = { "GlobalObject", &JSVariableObject::s_info, 0, ExecState::globalObjectTable, CREATE_METHOD_TABLE(JSGlobalObject) }; -const GlobalObjectMethodTable JSGlobalObject::s_globalObjectMethodTable = { &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript }; +const GlobalObjectMethodTable JSGlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript }; /* Source for JSGlobalObject.lut.h @begin globalObjectTable @@ -205,6 +205,10 @@ void JSGlobalObject::reset(JSValue prototype) m_callFunction.set(exec->globalData(), this, callFunction); m_applyFunction.set(exec->globalData(), this, applyFunction); m_objectPrototype.set(exec->globalData(), this, ObjectPrototype::create(exec, this, ObjectPrototype::createStructure(exec->globalData(), this, jsNull()))); + GetterSetter* protoAccessor = GetterSetter::create(exec); + protoAccessor->setGetter(exec->globalData(), JSFunction::create(exec, this, 0, Identifier(), globalFuncProtoGetter)); + protoAccessor->setSetter(exec->globalData(), JSFunction::create(exec, this, 0, Identifier(), globalFuncProtoSetter)); + m_objectPrototype->putDirectAccessor(exec->globalData(), exec->propertyNames().underscoreProto, protoAccessor, Accessor | DontEnum); m_functionPrototype->structure()->setPrototypeWithoutTransition(exec->globalData(), m_objectPrototype.get()); m_emptyObjectStructure.set(exec->globalData(), this, m_objectPrototype->inheritorID(exec->globalData())); diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h index b67ccb764..cbc436e1a 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.h +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h @@ -44,6 +44,7 @@ namespace JSC { class FunctionPrototype; class GetterSetter; class GlobalCodeBlock; + class LLIntOffsetsExtractor; class NativeErrorConstructor; class ProgramCodeBlock; class RegExpConstructor; @@ -56,6 +57,9 @@ namespace JSC { typedef Vector<ExecState*, 16> ExecStateStack; struct GlobalObjectMethodTable { + typedef bool (*AllowsAccessFromFunctionPtr)(const JSGlobalObject*, ExecState*); + AllowsAccessFromFunctionPtr allowsAccessFrom; + typedef bool (*SupportsProfilingFunctionPtr)(const JSGlobalObject*); SupportsProfilingFunctionPtr supportsProfiling; @@ -279,6 +283,7 @@ namespace JSC { const GlobalObjectMethodTable* globalObjectMethodTable() const { return m_globalObjectMethodTable; } + static bool allowsAccessFrom(const JSGlobalObject*, ExecState*) { return true; } static bool supportsProfiling(const JSGlobalObject*) { return false; } static bool supportsRichSourceInfo(const JSGlobalObject*) { return true; } @@ -336,6 +341,8 @@ namespace JSC { JS_EXPORT_PRIVATE void addStaticGlobals(GlobalPropertyInfo*, int count); private: + friend class LLIntOffsetsExtractor; + // FIXME: Fold reset into init. JS_EXPORT_PRIVATE void init(JSObject* thisValue); void reset(JSValue prototype); diff --git a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp index b82ab62ab..db8ee1d85 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp @@ -297,7 +297,7 @@ static double parseInt(const UString& s, const CharType* data, int radix) } if (number >= mantissaOverflowLowerBound) { if (radix == 10) - number = WTF::strtod(s.substringSharingImpl(firstDigitPosition, p - firstDigitPosition).utf8().data(), 0); + number = WTF::strtod<WTF::AllowTrailingJunk>(s.substringSharingImpl(firstDigitPosition, p - firstDigitPosition).utf8().data(), 0); else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32) number = parseIntOverflow(s.substringSharingImpl(firstDigitPosition, p - firstDigitPosition).utf8().data(), p - firstDigitPosition, radix); } @@ -369,7 +369,7 @@ static double jsStrDecimalLiteral(const CharType*& data, const CharType* end) } byteBuffer.append(0); char* endOfNumber; - double number = WTF::strtod(byteBuffer.data(), &endOfNumber); + double number = WTF::strtod<WTF::AllowTrailingJunk>(byteBuffer.data(), &endOfNumber); // Check if strtod found a number; if so return it. ptrdiff_t consumed = endOfNumber - byteBuffer.data(); @@ -714,4 +714,40 @@ EncodedJSValue JSC_HOST_CALL globalFuncThrowTypeError(ExecState* exec) return throwVMTypeError(exec); } +EncodedJSValue JSC_HOST_CALL globalFuncProtoGetter(ExecState* exec) +{ + if (!exec->thisValue().isObject()) + return JSValue::encode(exec->thisValue().synthesizePrototype(exec)); + + JSObject* thisObject = asObject(exec->thisValue()); + if (!thisObject->allowsAccessFrom(exec->trueCallerFrame())) + return JSValue::encode(jsUndefined()); + + return JSValue::encode(thisObject->prototype()); +} + +EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState* exec) +{ + JSValue value = exec->argument(0); + + // Setting __proto__ of a primitive should have no effect. + if (!exec->thisValue().isObject()) + return JSValue::encode(jsUndefined()); + + JSObject* thisObject = asObject(exec->thisValue()); + if (!thisObject->allowsAccessFrom(exec->trueCallerFrame())) + return JSValue::encode(jsUndefined()); + + // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla. + if (!value.isObject() && !value.isNull()) + return JSValue::encode(jsUndefined()); + + if (!thisObject->isExtensible()) + return throwVMError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError)); + + if (!thisObject->setPrototypeWithCycleCheck(exec->globalData(), value)) + throwError(exec, createError(exec, "cyclic __proto__ value")); + return JSValue::encode(jsUndefined()); +} + } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h index 1183dfac5..8833bf6d0 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h +++ b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h @@ -48,6 +48,8 @@ namespace JSC { EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState*); EncodedJSValue JSC_HOST_CALL globalFuncUnescape(ExecState*); EncodedJSValue JSC_HOST_CALL globalFuncThrowTypeError(ExecState*); + EncodedJSValue JSC_HOST_CALL globalFuncProtoGetter(ExecState*); + EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState*); static const double mantissaOverflowLowerBound = 9007199254740992.0; double parseIntOverflow(const LChar*, int length, int radix); diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp index ba2d2a52a..acc4a181e 100644 --- a/Source/JavaScriptCore/runtime/JSObject.cpp +++ b/Source/JavaScriptCore/runtime/JSObject.cpp @@ -24,7 +24,7 @@ #include "config.h" #include "JSObject.h" -#include "BumpSpaceInlineMethods.h" +#include "CopiedSpaceInlineMethods.h" #include "DatePrototype.h" #include "ErrorConstructor.h" #include "GetterSetter.h" @@ -48,6 +48,7 @@ ASSERT_CLASS_FITS_IN_CELL(JSNonFinalObject); ASSERT_CLASS_FITS_IN_CELL(JSFinalObject); ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSObject); +ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSFinalObject); const char* StrictModeReadonlyPropertyWriteError = "Attempted to assign to readonly property."; @@ -55,16 +56,6 @@ const ClassInfo JSObject::s_info = { "Object", 0, 0, 0, CREATE_METHOD_TABLE(JSOb const ClassInfo JSFinalObject::s_info = { "Object", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSFinalObject) }; -void JSFinalObject::destroy(JSCell* cell) -{ - jsCast<JSFinalObject*>(cell)->JSFinalObject::~JSFinalObject(); -} - -void JSNonFinalObject::destroy(JSCell* cell) -{ - jsCast<JSNonFinalObject*>(cell)->JSNonFinalObject::~JSNonFinalObject(); -} - static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode) { // Add properties from the static hashtables of properties @@ -84,11 +75,6 @@ static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* class } } -void JSObject::destroy(JSCell* cell) -{ - jsCast<JSObject*>(cell)->JSObject::~JSObject(); -} - void JSObject::visitChildren(JSCell* cell, SlotVisitor& visitor) { JSObject* thisObject = jsCast<JSObject*>(cell); @@ -146,47 +132,36 @@ void JSObject::put(JSCell* cell, ExecState* exec, const Identifier& propertyName ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject)); JSGlobalData& globalData = exec->globalData(); - if (propertyName == exec->propertyNames().underscoreProto) { - // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla. - if (!value.isObject() && !value.isNull()) - return; - - if (!thisObject->isExtensible()) { - if (slot.isStrictMode()) - throwTypeError(exec, StrictModeReadonlyPropertyWriteError); - return; - } - - if (!thisObject->setPrototypeWithCycleCheck(globalData, value)) - throwError(exec, createError(exec, "cyclic __proto__ value")); - return; - } - // Check if there are any setters or getters in the prototype chain JSValue prototype; - for (JSObject* obj = thisObject; !obj->structure()->hasGetterSetterProperties(); obj = asObject(prototype)) { - prototype = obj->prototype(); - if (prototype.isNull()) { - if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getJSFunction(value)) && slot.isStrictMode()) - throwTypeError(exec, StrictModeReadonlyPropertyWriteError); - return; + if (propertyName != exec->propertyNames().underscoreProto) { + for (JSObject* obj = thisObject; !obj->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) { + prototype = obj->prototype(); + if (prototype.isNull()) { + if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getJSFunction(value)) && slot.isStrictMode()) + throwTypeError(exec, StrictModeReadonlyPropertyWriteError); + return; + } } } - - unsigned attributes; - JSCell* specificValue; - if ((thisObject->structure()->get(globalData, propertyName, attributes, specificValue) != WTF::notFound) && attributes & ReadOnly) { - if (slot.isStrictMode()) - throwError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError)); - return; - } for (JSObject* obj = thisObject; ; obj = asObject(prototype)) { - if (JSValue gs = obj->getDirect(globalData, propertyName)) { + unsigned attributes; + JSCell* specificValue; + size_t offset = obj->structure()->get(globalData, propertyName, attributes, specificValue); + if (offset != WTF::notFound) { + if (attributes & ReadOnly) { + if (slot.isStrictMode()) + throwError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError)); + return; + } + + JSValue gs = obj->getDirectOffset(offset); if (gs.isGetterSetter()) { JSObject* setterFunc = asGetterSetter(gs)->setter(); if (!setterFunc) { - throwSetterError(exec); + if (slot.isStrictMode()) + throwSetterError(exec); return; } @@ -229,10 +204,31 @@ void JSObject::putDirectVirtual(JSObject* object, ExecState* exec, const Identif object->putDirectInternal<PutModeDefineOwnProperty>(exec->globalData(), propertyName, value, attributes, slot, getJSFunction(value)); } +bool JSObject::setPrototypeWithCycleCheck(JSGlobalData& globalData, JSValue prototype) +{ + JSValue checkFor = this; + if (this->isGlobalObject()) + checkFor = static_cast<JSGlobalObject*>(this)->globalExec()->thisValue(); + + JSValue nextPrototype = prototype; + while (nextPrototype && nextPrototype.isObject()) { + if (nextPrototype == checkFor) + return false; + nextPrototype = asObject(nextPrototype)->prototype(); + } + setPrototype(globalData, prototype); + return true; +} + +bool JSObject::allowsAccessFrom(ExecState* exec) +{ + JSGlobalObject* globalObject = isGlobalThis() ? static_cast<JSGlobalThis*>(this)->unwrappedObject() : this->globalObject(); + return globalObject->globalObjectMethodTable()->allowsAccessFrom(globalObject, exec); +} + void JSObject::putDirectAccessor(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes) { ASSERT(value.isGetterSetter() && (attributes & Accessor)); - ASSERT(propertyName != globalData.propertyNames->underscoreProto); PutPropertySlot slot; putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, attributes, slot, getJSFunction(value)); @@ -243,7 +239,10 @@ void JSObject::putDirectAccessor(JSGlobalData& globalData, const Identifier& pro if (slot.type() != PutPropertySlot::NewProperty) setStructure(globalData, Structure::attributeChangeTransition(globalData, structure(), propertyName, attributes)); - structure()->setHasGetterSetterProperties(true); + if (attributes & ReadOnly) + structure()->setContainsReadOnlyProperties(); + + structure()->setHasGetterSetterProperties(propertyName == globalData.propertyNames->underscoreProto); } bool JSObject::hasProperty(ExecState* exec, const Identifier& propertyName) const @@ -269,7 +268,7 @@ bool JSObject::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& p unsigned attributes; JSCell* specificValue; if (thisObject->structure()->get(exec->globalData(), propertyName, attributes, specificValue) != WTF::notFound) { - if ((attributes & DontDelete)) + if (attributes & DontDelete && !exec->globalData().isInDefineOwnProperty()) return false; thisObject->removeDirect(exec->globalData(), propertyName); return true; @@ -277,7 +276,7 @@ bool JSObject::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& p // Look in the static hashtable of properties const HashEntry* entry = thisObject->findPropertyHashEntry(exec, propertyName); - if (entry && entry->attributes() & DontDelete) + if (entry && entry->attributes() & DontDelete && !exec->globalData().isInDefineOwnProperty()) return false; // this builtin property can't be deleted // FIXME: Should the code here actually do some deletion? @@ -479,6 +478,8 @@ void JSObject::freeze(JSGlobalData& globalData) void JSObject::preventExtensions(JSGlobalData& globalData) { + if (isJSArray(this)) + asArray(this)->enterDictionaryMode(globalData); if (isExtensible()) setStructure(globalData, Structure::preventExtensionsTransition(globalData, structure())); } @@ -623,6 +624,8 @@ static bool putDescriptor(ExecState* exec, JSObject* target, const Identifier& p else if (oldDescriptor.value()) newValue = oldDescriptor.value(); target->putDirect(exec->globalData(), propertyName, newValue, attributes & ~Accessor); + if (attributes & ReadOnly) + target->structure()->setContainsReadOnlyProperties(); return true; } attributes &= ~ReadOnly; @@ -641,12 +644,30 @@ static bool putDescriptor(ExecState* exec, JSObject* target, const Identifier& p return true; } +class DefineOwnPropertyScope { +public: + DefineOwnPropertyScope(ExecState* exec) + : m_globalData(exec->globalData()) + { + m_globalData.setInDefineOwnProperty(true); + } + + ~DefineOwnPropertyScope() + { + m_globalData.setInDefineOwnProperty(false); + } + +private: + JSGlobalData& m_globalData; +}; + bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool throwException) { - // __proto__ is magic; we don't currently support setting it as a regular property. - // Silent filter out calls to set __proto__ at an early stage; pretend all is okay. - if (propertyName == exec->propertyNames().underscoreProto) - return true; + // Track on the globaldata that we're in define property. + // Currently DefineOwnProperty uses delete to remove properties when they are being replaced + // (particularly when changing attributes), however delete won't allow non-configurable (i.e. + // DontDelete) properties to be deleted. For now, we can use this flag to make this work. + DefineOwnPropertyScope scope(exec); // If we have a new property we can just put it on normally PropertyDescriptor current; @@ -711,21 +732,15 @@ bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, const Identi return false; } if (!current.writable()) { - if (descriptor.value() || !sameValue(exec, current.value(), descriptor.value())) { + if (descriptor.value() && !sameValue(exec, current.value(), descriptor.value())) { if (throwException) throwError(exec, createTypeError(exec, "Attempting to change value of a readonly property.")); return false; } } - } else if (current.attributesEqual(descriptor)) { - if (!descriptor.value()) - return true; - PutPropertySlot slot; - object->methodTable()->put(object, exec, propertyName, descriptor.value(), slot); - if (exec->hadException()) - return false; - return true; } + if (current.attributesEqual(descriptor) && !descriptor.value()) + return true; object->methodTable()->deleteProperty(object, exec, propertyName); return putDescriptor(exec, object, propertyName, descriptor, current.attributesWithOverride(descriptor), current); } @@ -748,15 +763,14 @@ bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, const Identi if (!accessor) return false; GetterSetter* getterSetter = asGetterSetter(accessor); - if (current.attributesEqual(descriptor)) { - if (descriptor.setterPresent()) - getterSetter->setSetter(exec->globalData(), descriptor.setterObject()); - if (descriptor.getterPresent()) - getterSetter->setGetter(exec->globalData(), descriptor.getterObject()); + if (descriptor.setterPresent()) + getterSetter->setSetter(exec->globalData(), descriptor.setterObject()); + if (descriptor.getterPresent()) + getterSetter->setGetter(exec->globalData(), descriptor.getterObject()); + if (current.attributesEqual(descriptor)) return true; - } object->methodTable()->deleteProperty(object, exec, propertyName); - unsigned attrs = current.attributesWithOverride(descriptor); + unsigned attrs = descriptor.attributesOverridingCurrent(current); object->putDirectAccessor(exec->globalData(), propertyName, getterSetter, attrs | Accessor); return true; } diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h index e9194fa01..c117cffaf 100644 --- a/Source/JavaScriptCore/runtime/JSObject.h +++ b/Source/JavaScriptCore/runtime/JSObject.h @@ -49,6 +49,7 @@ namespace JSC { class GetterSetter; class HashEntry; class InternalFunction; + class LLIntOffsetsExtractor; class MarkedBlock; class PropertyDescriptor; class PropertyNameArray; @@ -84,8 +85,6 @@ namespace JSC { public: typedef JSCell Base; - JS_EXPORT_PRIVATE static void destroy(JSCell*); - JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); JS_EXPORT_PRIVATE static UString className(const JSObject*); @@ -107,6 +106,8 @@ namespace JSC { JS_EXPORT_PRIVATE static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&); JS_EXPORT_PRIVATE static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&); + bool allowsAccessFrom(ExecState*); + JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); JS_EXPORT_PRIVATE static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue); @@ -264,6 +265,8 @@ namespace JSC { JSObject(JSGlobalData&, Structure*, PropertyStorage inlineStorage); private: + friend class LLIntOffsetsExtractor; + // Nobody should ever ask any of these questions on something already known to be a JSObject. using JSCell::isAPIValueWrapper; using JSCell::isGetterSetter; @@ -323,8 +326,6 @@ COMPILE_ASSERT((JSFinalObject_inlineStorageCapacity >= JSNonFinalObject_inlineSt return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } - JS_EXPORT_PRIVATE static void destroy(JSCell*); - protected: explicit JSNonFinalObject(JSGlobalData& globalData, Structure* structure) : JSObject(globalData, structure, m_inlineStorage) @@ -343,6 +344,8 @@ COMPILE_ASSERT((JSFinalObject_inlineStorageCapacity >= JSNonFinalObject_inlineSt WriteBarrier<Unknown> m_inlineStorage[JSNonFinalObject_inlineStorageCapacity]; }; + class JSFinalObject; + // JSFinalObject is a type of JSObject that contains sufficent internal // storage to fully make use of the colloctor cell containing it. class JSFinalObject : public JSObject { @@ -351,13 +354,7 @@ COMPILE_ASSERT((JSFinalObject_inlineStorageCapacity >= JSNonFinalObject_inlineSt public: typedef JSObject Base; - static JSFinalObject* create(ExecState* exec, Structure* structure) - { - JSFinalObject* finalObject = new (NotNull, allocateCell<JSFinalObject>(*exec->heap())) JSFinalObject(exec->globalData(), structure); - finalObject->finishCreation(exec->globalData()); - return finalObject; - } - + static JSFinalObject* create(ExecState*, Structure*); static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) { return Structure::create(globalData, globalObject, prototype, TypeInfo(FinalObjectType, StructureFlags), &s_info); @@ -374,9 +371,9 @@ COMPILE_ASSERT((JSFinalObject_inlineStorageCapacity >= JSNonFinalObject_inlineSt ASSERT(classInfo()); } - static void destroy(JSCell*); - private: + friend class LLIntOffsetsExtractor; + explicit JSFinalObject(JSGlobalData& globalData, Structure* structure) : JSObject(globalData, structure, m_inlineStorage) { @@ -387,6 +384,13 @@ COMPILE_ASSERT((JSFinalObject_inlineStorageCapacity >= JSNonFinalObject_inlineSt WriteBarrierBase<Unknown> m_inlineStorage[JSFinalObject_inlineStorageCapacity]; }; +inline JSFinalObject* JSFinalObject::create(ExecState* exec, Structure* structure) +{ + JSFinalObject* finalObject = new (NotNull, allocateCell<JSFinalObject>(*exec->heap())) JSFinalObject(exec->globalData(), structure); + finalObject->finishCreation(exec->globalData()); + return finalObject; +} + inline bool isJSFinalObject(JSCell* cell) { return cell->classInfo() == &JSFinalObject::s_info; @@ -489,19 +493,6 @@ inline JSValue JSObject::prototype() const return structure()->storedPrototype(); } -inline bool JSObject::setPrototypeWithCycleCheck(JSGlobalData& globalData, JSValue prototype) -{ - JSValue nextPrototypeValue = prototype; - while (nextPrototypeValue && nextPrototypeValue.isObject()) { - JSObject* nextPrototype = asObject(nextPrototypeValue)->unwrappedObject(); - if (nextPrototype == this) - return false; - nextPrototypeValue = nextPrototype->prototype(); - } - setPrototype(globalData, prototype); - return true; -} - inline void JSObject::setPrototype(JSGlobalData& globalData, JSValue prototype) { ASSERT(prototype); @@ -553,12 +544,6 @@ ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, const Ide return true; } - // non-standard Netscape extension - if (propertyName == exec->propertyNames().underscoreProto) { - slot.setValue(prototype()); - return true; - } - return false; } @@ -806,8 +791,6 @@ inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName, Pro { if (UNLIKELY(!isCell())) { JSObject* prototype = synthesizePrototype(exec); - if (propertyName == exec->propertyNames().underscoreProto) - return prototype; if (!prototype->getPropertySlot(exec, propertyName, slot)) return jsUndefined(); return slot.getValue(exec, propertyName); diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h index d52e3ea61..7530d7532 100644 --- a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h +++ b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h @@ -38,6 +38,7 @@ namespace JSC { class Identifier; class JSObject; + class LLIntOffsetsExtractor; class JSPropertyNameIterator : public JSCell { friend class JIT; @@ -96,6 +97,8 @@ namespace JSC { } private: + friend class LLIntOffsetsExtractor; + JSPropertyNameIterator(ExecState*, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlot); WriteBarrier<Structure> m_cachedStructure; diff --git a/Source/JavaScriptCore/runtime/JSString.cpp b/Source/JavaScriptCore/runtime/JSString.cpp index 4e98f9d18..cfa7d03b4 100644 --- a/Source/JavaScriptCore/runtime/JSString.cpp +++ b/Source/JavaScriptCore/runtime/JSString.cpp @@ -189,7 +189,7 @@ void JSString::outOfMemory(ExecState* exec) const { for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) m_fibers[i].clear(); - ASSERT(!isRope()); + ASSERT(isRope()); ASSERT(m_value == UString()); if (exec) throwOutOfMemoryError(exec); @@ -253,10 +253,6 @@ bool JSString::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifie // This function should only be called by JSValue::get. if (thisObject->getStringPropertySlot(exec, propertyName, slot)) return true; - if (propertyName == exec->propertyNames().underscoreProto) { - slot.setValue(exec->lexicalGlobalObject()->stringPrototype()); - return true; - } slot.setBase(thisObject); JSObject* object; for (JSValue prototype = exec->lexicalGlobalObject()->stringPrototype(); !prototype.isNull(); prototype = object->prototype()) { diff --git a/Source/JavaScriptCore/runtime/JSString.h b/Source/JavaScriptCore/runtime/JSString.h index c0637a6e0..32a32788a 100644 --- a/Source/JavaScriptCore/runtime/JSString.h +++ b/Source/JavaScriptCore/runtime/JSString.h @@ -32,6 +32,7 @@ namespace JSC { class JSString; + class LLIntOffsetsExtractor; JSString* jsEmptyString(JSGlobalData*); JSString* jsEmptyString(ExecState*); @@ -240,6 +241,8 @@ namespace JSC { static void visitChildren(JSCell*, SlotVisitor&); private: + friend class LLIntOffsetsExtractor; + JS_EXPORT_PRIVATE void resolveRope(ExecState*) const; void resolveRopeSlowCase8(LChar*) const; void resolveRopeSlowCase(UChar*) const; diff --git a/Source/JavaScriptCore/runtime/JSTypeInfo.h b/Source/JavaScriptCore/runtime/JSTypeInfo.h index 3e23aa253..83a3594db 100644 --- a/Source/JavaScriptCore/runtime/JSTypeInfo.h +++ b/Source/JavaScriptCore/runtime/JSTypeInfo.h @@ -34,6 +34,8 @@ namespace JSC { + class LLIntOffsetsExtractor; + static const unsigned MasqueradesAsUndefined = 1; // WebCore uses MasqueradesAsUndefined to make document.all undetectable. static const unsigned ImplementsHasInstance = 1 << 1; static const unsigned OverridesHasInstance = 1 << 2; @@ -87,6 +89,8 @@ namespace JSC { } private: + friend class LLIntOffsetsExtractor; + bool isSetOnFlags1(unsigned flag) const { ASSERT(flag <= (1 << 7)); return m_flags & flag; } bool isSetOnFlags2(unsigned flag) const { ASSERT(flag >= (1 << 8)); return m_flags2 & (flag >> 8); } diff --git a/Source/JavaScriptCore/runtime/JSValue.cpp b/Source/JavaScriptCore/runtime/JSValue.cpp index 72cf5a8d5..e3843f02b 100644 --- a/Source/JavaScriptCore/runtime/JSValue.cpp +++ b/Source/JavaScriptCore/runtime/JSValue.cpp @@ -118,7 +118,7 @@ JSObject* JSValue::synthesizePrototype(ExecState* exec) const char* JSValue::description() { - static const size_t size = 64; + static const size_t size = 128; static char description[size]; if (!*this) @@ -127,14 +127,14 @@ char* JSValue::description() snprintf(description, size, "Int32: %d", asInt32()); else if (isDouble()) { #if USE(JSVALUE64) - snprintf(description, size, "Double: %lf, %lx", asDouble(), reinterpretDoubleToIntptr(asDouble())); + snprintf(description, size, "Double: %lx, %lf", reinterpretDoubleToIntptr(asDouble()), asDouble()); #else union { double asDouble; uint32_t asTwoInt32s[2]; } u; u.asDouble = asDouble(); - snprintf(description, size, "Double: %lf, %08x:%08x", asDouble(), u.asTwoInt32s[1], u.asTwoInt32s[0]); + snprintf(description, size, "Double: %08x:%08x, %lf", u.asTwoInt32s[1], u.asTwoInt32s[0], asDouble()); #endif } else if (isCell()) snprintf(description, size, "Cell: %p", asCell()); diff --git a/Source/JavaScriptCore/runtime/JSValue.h b/Source/JavaScriptCore/runtime/JSValue.h index b18c181f5..9f797e05d 100644 --- a/Source/JavaScriptCore/runtime/JSValue.h +++ b/Source/JavaScriptCore/runtime/JSValue.h @@ -55,6 +55,9 @@ namespace JSC { class SpeculativeJIT; } #endif + namespace LLInt { + class Data; + } struct ClassInfo; struct Instruction; @@ -118,6 +121,7 @@ namespace JSC { friend class DFG::OSRExitCompiler; friend class DFG::SpeculativeJIT; #endif + friend class LLInt::Data; public: static EncodedJSValue encode(JSValue); @@ -234,6 +238,8 @@ namespace JSC { char* description(); + JS_EXPORT_PRIVATE JSObject* synthesizePrototype(ExecState*) const; + private: template <class T> JSValue(WriteBarrierBase<T>); @@ -246,7 +252,6 @@ namespace JSC { JS_EXPORT_PRIVATE JSObject* toObjectSlowCase(ExecState*, JSGlobalObject*) const; JS_EXPORT_PRIVATE JSObject* toThisObjectSlowCase(ExecState*) const; - JS_EXPORT_PRIVATE JSObject* synthesizePrototype(ExecState*) const; JSObject* synthesizeObject(ExecState*) const; #if USE(JSVALUE32_64) diff --git a/Source/JavaScriptCore/runtime/JSVariableObject.h b/Source/JavaScriptCore/runtime/JSVariableObject.h index c1d05ff74..8d058f1fc 100644 --- a/Source/JavaScriptCore/runtime/JSVariableObject.h +++ b/Source/JavaScriptCore/runtime/JSVariableObject.h @@ -38,10 +38,12 @@ namespace JSC { + class LLIntOffsetsExtractor; class Register; class JSVariableObject : public JSNonFinalObject { friend class JIT; + friend class LLIntOffsetsExtractor; public: typedef JSNonFinalObject Base; diff --git a/Source/JavaScriptCore/runtime/LiteralParser.cpp b/Source/JavaScriptCore/runtime/LiteralParser.cpp index b22b81503..3bde3ff08 100644 --- a/Source/JavaScriptCore/runtime/LiteralParser.cpp +++ b/Source/JavaScriptCore/runtime/LiteralParser.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2012 Mathias Bynens (mathias@qiwi.be) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -294,7 +295,7 @@ ALWAYS_INLINE TokenType LiteralParser<LChar>::Lexer::lexIdentifier(LiteralParser template <> ALWAYS_INLINE TokenType LiteralParser<UChar>::Lexer::lexIdentifier(LiteralParserToken<UChar>& token) { - while (m_ptr < m_end && (isASCIIAlphanumeric(*m_ptr) || *m_ptr == '_' || *m_ptr == '$')) + while (m_ptr < m_end && (isASCIIAlphanumeric(*m_ptr) || *m_ptr == '_' || *m_ptr == '$' || *m_ptr == 0x200C || *m_ptr == 0x200D)) m_ptr++; token.stringIs8Bit = 0; token.stringToken16 = token.start; @@ -536,7 +537,7 @@ TokenType LiteralParser<CharType>::Lexer::lexNumber(LiteralParserToken<CharType> } buffer[i] = 0; char* end; - token.numberToken = WTF::strtod(buffer.data(), &end); + token.numberToken = WTF::strtod<WTF::AllowTrailingJunk>(buffer.data(), &end); ASSERT(buffer.data() + (token.end - token.start) == end); return TokNumber; } diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp index d96c1de7f..b7dd71655 100644 --- a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp +++ b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp @@ -138,11 +138,10 @@ EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState* exec) { if (!exec->argument(0).isObject()) return throwVMError(exec, createTypeError(exec, "Requested prototype of a value that is not an object.")); - - // This uses JSValue::get() instead of directly accessing the prototype from the object - // (using JSObject::prototype()) in order to allow objects to override the behavior, such - // as returning jsUndefined() for cross-origin access. - return JSValue::encode(exec->argument(0).get(exec, exec->propertyNames().underscoreProto)); + JSObject* object = asObject(exec->argument(0)); + if (!object->allowsAccessFrom(exec->trueCallerFrame())) + return JSValue::encode(jsUndefined()); + return JSValue::encode(object->prototype()); } EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState* exec) @@ -342,9 +341,7 @@ EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState* exec) { if (!exec->argument(0).isObject()) return throwVMError(exec, createTypeError(exec, "Properties can only be defined on Objects.")); - if (!exec->argument(1).isObject()) - return throwVMError(exec, createTypeError(exec, "Property descriptor list must be an Object.")); - return JSValue::encode(defineProperties(exec, asObject(exec->argument(0)), asObject(exec->argument(1)))); + return JSValue::encode(defineProperties(exec, asObject(exec->argument(0)), exec->argument(1).toObject(exec))); } EncodedJSValue JSC_HOST_CALL objectConstructorCreate(ExecState* exec) @@ -362,19 +359,79 @@ EncodedJSValue JSC_HOST_CALL objectConstructorCreate(ExecState* exec) EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState* exec) { + // 1. If Type(O) is not Object throw a TypeError exception. JSValue obj = exec->argument(0); if (!obj.isObject()) return throwVMError(exec, createTypeError(exec, "Object.seal can only be called on Objects.")); - asObject(obj)->seal(exec->globalData()); + JSObject* object = asObject(obj); + + if (isJSFinalObject(object)) { + object->seal(exec->globalData()); + return JSValue::encode(obj); + } + + // 2. For each named own property name P of O, + PropertyNameArray properties(exec); + object->methodTable()->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties); + PropertyNameArray::const_iterator end = properties.end(); + for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) { + // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P. + PropertyDescriptor desc; + if (!object->methodTable()->getOwnPropertyDescriptor(object, exec, *iter, desc)) + continue; + // b. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false. + desc.setConfigurable(false); + // c. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments. + object->methodTable()->defineOwnProperty(object, exec, *iter, desc, true); + if (exec->hadException()) + return JSValue::encode(obj); + } + + // 3. Set the [[Extensible]] internal property of O to false. + object->preventExtensions(exec->globalData()); + + // 4. Return O. return JSValue::encode(obj); } EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState* exec) { + // 1. If Type(O) is not Object throw a TypeError exception. JSValue obj = exec->argument(0); if (!obj.isObject()) return throwVMError(exec, createTypeError(exec, "Object.freeze can only be called on Objects.")); - asObject(obj)->freeze(exec->globalData()); + JSObject* object = asObject(obj); + + if (isJSFinalObject(object)) { + object->freeze(exec->globalData()); + return JSValue::encode(obj); + } + + // 2. For each named own property name P of O, + PropertyNameArray properties(exec); + object->methodTable()->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties); + PropertyNameArray::const_iterator end = properties.end(); + for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) { + // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P. + PropertyDescriptor desc; + if (!object->methodTable()->getOwnPropertyDescriptor(object, exec, *iter, desc)) + continue; + // b. If IsDataDescriptor(desc) is true, then + // i. If desc.[[Writable]] is true, set desc.[[Writable]] to false. + if (desc.isDataDescriptor()) + desc.setWritable(false); + // c. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false. + desc.setConfigurable(false); + // d. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments. + object->methodTable()->defineOwnProperty(object, exec, *iter, desc, true); + if (exec->hadException()) + return JSValue::encode(obj); + } + + // 3. Set the [[Extensible]] internal property of O to false. + object->preventExtensions(exec->globalData()); + + // 4. Return O. return JSValue::encode(obj); } @@ -389,18 +446,63 @@ EncodedJSValue JSC_HOST_CALL objectConstructorPreventExtensions(ExecState* exec) EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState* exec) { + // 1. If Type(O) is not Object throw a TypeError exception. JSValue obj = exec->argument(0); if (!obj.isObject()) return throwVMError(exec, createTypeError(exec, "Object.isSealed can only be called on Objects.")); - return JSValue::encode(jsBoolean(asObject(obj)->isSealed(exec->globalData()))); + JSObject* object = asObject(obj); + + if (isJSFinalObject(object)) + return JSValue::encode(jsBoolean(object->isSealed(exec->globalData()))); + + // 2. For each named own property name P of O, + PropertyNameArray properties(exec); + object->methodTable()->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties); + PropertyNameArray::const_iterator end = properties.end(); + for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) { + // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P. + PropertyDescriptor desc; + if (!object->methodTable()->getOwnPropertyDescriptor(object, exec, *iter, desc)) + continue; + // b. If desc.[[Configurable]] is true, then return false. + if (desc.configurable()) + return JSValue::encode(jsBoolean(false)); + } + + // 3. If the [[Extensible]] internal property of O is false, then return true. + // 4. Otherwise, return false. + return JSValue::encode(jsBoolean(!object->isExtensible())); } EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState* exec) { + // 1. If Type(O) is not Object throw a TypeError exception. JSValue obj = exec->argument(0); if (!obj.isObject()) return throwVMError(exec, createTypeError(exec, "Object.isFrozen can only be called on Objects.")); - return JSValue::encode(jsBoolean(asObject(obj)->isFrozen(exec->globalData()))); + JSObject* object = asObject(obj); + + if (isJSFinalObject(object)) + return JSValue::encode(jsBoolean(object->isFrozen(exec->globalData()))); + + // 2. For each named own property name P of O, + PropertyNameArray properties(exec); + object->methodTable()->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties); + PropertyNameArray::const_iterator end = properties.end(); + for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) { + // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P. + PropertyDescriptor desc; + if (!object->methodTable()->getOwnPropertyDescriptor(object, exec, *iter, desc)) + continue; + // b. If IsDataDescriptor(desc) is true then + // i. If desc.[[Writable]] is true, return false. c. If desc.[[Configurable]] is true, then return false. + if ((desc.isDataDescriptor() && desc.writable()) || desc.configurable()) + return JSValue::encode(jsBoolean(false)); + } + + // 3. If the [[Extensible]] internal property of O is false, then return true. + // 4. Otherwise, return false. + return JSValue::encode(jsBoolean(!object->isExtensible())); } EncodedJSValue JSC_HOST_CALL objectConstructorIsExtensible(ExecState* exec) diff --git a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp index 674bd7b7d..6ad312c7c 100644 --- a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp @@ -80,7 +80,7 @@ void ObjectPrototype::finishCreation(JSGlobalData& globalData, JSGlobalObject*) void ObjectPrototype::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) { ObjectPrototype* thisObject = jsCast<ObjectPrototype*>(cell); - JSNonFinalObject::put(cell, exec, propertyName, value, slot); + Base::put(cell, exec, propertyName, value, slot); if (thisObject->m_hasNoPropertiesWithUInt32Names) { bool isUInt32; @@ -89,12 +89,26 @@ void ObjectPrototype::put(JSCell* cell, ExecState* exec, const Identifier& prope } } +bool ObjectPrototype::defineOwnProperty(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool shouldThrow) +{ + ObjectPrototype* thisObject = jsCast<ObjectPrototype*>(object); + bool result = Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow); + + if (thisObject->m_hasNoPropertiesWithUInt32Names) { + bool isUInt32; + propertyName.toUInt32(isUInt32); + thisObject->m_hasNoPropertiesWithUInt32Names = !isUInt32; + } + + return result; +} + bool ObjectPrototype::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, PropertySlot& slot) { ObjectPrototype* thisObject = jsCast<ObjectPrototype*>(cell); if (thisObject->m_hasNoPropertiesWithUInt32Names) return false; - return JSNonFinalObject::getOwnPropertySlotByIndex(thisObject, exec, propertyName, slot); + return Base::getOwnPropertySlotByIndex(thisObject, exec, propertyName, slot); } bool ObjectPrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot &slot) diff --git a/Source/JavaScriptCore/runtime/ObjectPrototype.h b/Source/JavaScriptCore/runtime/ObjectPrototype.h index 4c49e97a7..b9b8a30d4 100644 --- a/Source/JavaScriptCore/runtime/ObjectPrototype.h +++ b/Source/JavaScriptCore/runtime/ObjectPrototype.h @@ -51,6 +51,7 @@ namespace JSC { private: ObjectPrototype(ExecState*, Structure*); static void put(JSCell*, ExecState*, const Identifier&, JSValue, PutPropertySlot&); + static bool defineOwnProperty(JSObject*, ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow); static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&); static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&); diff --git a/Source/JavaScriptCore/runtime/Options.cpp b/Source/JavaScriptCore/runtime/Options.cpp index ddfba6e7c..5500508cf 100644 --- a/Source/JavaScriptCore/runtime/Options.cpp +++ b/Source/JavaScriptCore/runtime/Options.cpp @@ -52,6 +52,10 @@ unsigned maximumFunctionForConstructInlineCandidateInstructionCount; unsigned maximumInliningDepth; +int32_t executionCounterValueForJITAfterWarmUp; +int32_t executionCounterValueForDontJITAnytimeSoon; +int32_t executionCounterValueForJITSoon; + int32_t executionCounterValueForOptimizeAfterWarmUp; int32_t executionCounterValueForOptimizeAfterLongWarmUp; int32_t executionCounterValueForDontOptimizeAnytimeSoon; @@ -137,6 +141,10 @@ void initializeOptions() SET(maximumInliningDepth, 5); + SET(executionCounterValueForJITAfterWarmUp, -100); + SET(executionCounterValueForDontJITAnytimeSoon, std::numeric_limits<int32_t>::min()); + SET(executionCounterValueForJITSoon, -100); + SET(executionCounterValueForOptimizeAfterWarmUp, -1000); SET(executionCounterValueForOptimizeAfterLongWarmUp, -5000); SET(executionCounterValueForDontOptimizeAnytimeSoon, std::numeric_limits<int32_t>::min()); @@ -185,6 +193,8 @@ void initializeOptions() if (cpusToUse < 1) cpusToUse = 1; + cpusToUse = 1; + SET(numberOfGCMarkers, cpusToUse); ASSERT(executionCounterValueForDontOptimizeAnytimeSoon <= executionCounterValueForOptimizeAfterLongWarmUp); diff --git a/Source/JavaScriptCore/runtime/Options.h b/Source/JavaScriptCore/runtime/Options.h index feebd37bb..b9e68f90c 100644 --- a/Source/JavaScriptCore/runtime/Options.h +++ b/Source/JavaScriptCore/runtime/Options.h @@ -37,6 +37,10 @@ extern unsigned maximumFunctionForConstructInlineCandidateInstructionCount; extern unsigned maximumInliningDepth; // Depth of inline stack, so 1 = no inlining, 2 = one level, etc. +extern int32_t executionCounterValueForJITAfterWarmUp; +extern int32_t executionCounterValueForDontJITAnytimeSoon; +extern int32_t executionCounterValueForJITSoon; + extern int32_t executionCounterValueForOptimizeAfterWarmUp; extern int32_t executionCounterValueForOptimizeAfterLongWarmUp; extern int32_t executionCounterValueForDontOptimizeAnytimeSoon; diff --git a/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp b/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp index e3458e4b9..0cb629584 100644 --- a/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp +++ b/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp @@ -217,12 +217,16 @@ unsigned PropertyDescriptor::attributesWithOverride(const PropertyDescriptor& ot newAttributes ^= DontDelete; if (sharedSeen & EnumerablePresent && mismatch & DontEnum) newAttributes ^= DontEnum; + if (isAccessorDescriptor() && other.isDataDescriptor()) + newAttributes |= ReadOnly; return newAttributes; } unsigned PropertyDescriptor::attributesOverridingCurrent(const PropertyDescriptor& current) const { unsigned currentAttributes = current.m_attributes; + if (isDataDescriptor() && current.isAccessorDescriptor()) + currentAttributes |= ReadOnly; unsigned overrideMask = 0; if (writablePresent()) overrideMask |= ReadOnly; diff --git a/Source/JavaScriptCore/runtime/RegExp.cpp b/Source/JavaScriptCore/runtime/RegExp.cpp index 69bca5df0..2b7feb4b5 100644 --- a/Source/JavaScriptCore/runtime/RegExp.cpp +++ b/Source/JavaScriptCore/runtime/RegExp.cpp @@ -413,24 +413,24 @@ void RegExp::matchCompareWithInterpreter(const UString& s, int startOffset, int* differences++; if (differences) { - fprintf(stderr, "RegExp Discrepency for /%s/\n string input ", pattern().utf8().data()); + dataLog("RegExp Discrepency for /%s/\n string input ", pattern().utf8().data()); unsigned segmentLen = s.length() - static_cast<unsigned>(startOffset); - fprintf(stderr, (segmentLen < 150) ? "\"%s\"\n" : "\"%148s...\"\n", s.utf8().data() + startOffset); + dataLog((segmentLen < 150) ? "\"%s\"\n" : "\"%148s...\"\n", s.utf8().data() + startOffset); if (jitResult != interpreterResult) { - fprintf(stderr, " JIT result = %d, blah interpreted result = %d\n", jitResult, interpreterResult); + dataLog(" JIT result = %d, blah interpreted result = %d\n", jitResult, interpreterResult); differences--; } else { - fprintf(stderr, " Correct result = %d\n", jitResult); + dataLog(" Correct result = %d\n", jitResult); } if (differences) { for (unsigned j = 2, i = 0; i < m_numSubpatterns; j +=2, i++) { if (offsetVector[j] != interpreterOffsetVector[j]) - fprintf(stderr, " JIT offset[%d] = %d, interpreted offset[%d] = %d\n", j, offsetVector[j], j, interpreterOffsetVector[j]); + dataLog(" JIT offset[%d] = %d, interpreted offset[%d] = %d\n", j, offsetVector[j], j, interpreterOffsetVector[j]); if ((offsetVector[j] >= 0) && (offsetVector[j+1] != interpreterOffsetVector[j+1])) - fprintf(stderr, " JIT offset[%d] = %d, interpreted offset[%d] = %d\n", j+1, offsetVector[j+1], j+1, interpreterOffsetVector[j+1]); + dataLog(" JIT offset[%d] = %d, interpreted offset[%d] = %d\n", j+1, offsetVector[j+1], j+1, interpreterOffsetVector[j+1]); } } } diff --git a/Source/JavaScriptCore/runtime/RegExpCache.cpp b/Source/JavaScriptCore/runtime/RegExpCache.cpp index cd96301db..d5edbbc7f 100644 --- a/Source/JavaScriptCore/runtime/RegExpCache.cpp +++ b/Source/JavaScriptCore/runtime/RegExpCache.cpp @@ -46,7 +46,7 @@ RegExp* RegExpCache::lookupOrCreate(const UString& patternString, RegExpFlags fl // We need to do a second lookup to add the RegExp as // allocating it may have caused a gc cycle, which in // turn may have removed items from the cache. - m_weakCache.add(key, Weak<RegExp>(*m_globalData, regExp, this)); + m_weakCache.add(key, PassWeak<RegExp>(*m_globalData, regExp, this)); return regExp; } diff --git a/Source/JavaScriptCore/runtime/SamplingCounter.cpp b/Source/JavaScriptCore/runtime/SamplingCounter.cpp index e5fb25a93..abed763ca 100644 --- a/Source/JavaScriptCore/runtime/SamplingCounter.cpp +++ b/Source/JavaScriptCore/runtime/SamplingCounter.cpp @@ -35,10 +35,10 @@ void AbstractSamplingCounter::dump() { #if ENABLE(SAMPLING_COUNTERS) if (s_abstractSamplingCounterChain != &s_abstractSamplingCounterChainEnd) { - printf("\nSampling Counter Values:\n"); + dataLog("\nSampling Counter Values:\n"); for (AbstractSamplingCounter* currCounter = s_abstractSamplingCounterChain; (currCounter != &s_abstractSamplingCounterChainEnd); currCounter = currCounter->m_next) - printf("\t%s\t: %lld\n", currCounter->m_name, currCounter->m_counter); - printf("\n\n"); + dataLog("\t%s\t: %lld\n", currCounter->m_name, currCounter->m_counter); + dataLog("\n\n"); } s_completed = true; #endif diff --git a/Source/JavaScriptCore/runtime/SamplingCounter.h b/Source/JavaScriptCore/runtime/SamplingCounter.h index 329a5cfd3..8413b5458 100644 --- a/Source/JavaScriptCore/runtime/SamplingCounter.h +++ b/Source/JavaScriptCore/runtime/SamplingCounter.h @@ -159,7 +159,7 @@ public: ~DeletableSamplingCounter() { if (!s_completed) - fprintf(stderr, "DeletableSamplingCounter \"%s\" deleted early (with count %lld)\n", m_name, m_counter); + dataFile("DeletableSamplingCounter \"%s\" deleted early (with count %lld)\n", m_name, m_counter); // Our m_referer pointer should know where the pointer to this node is, // and m_next should know that this node is the previous node in the list. ASSERT(*m_referer == this); diff --git a/Source/JavaScriptCore/runtime/ScopeChain.cpp b/Source/JavaScriptCore/runtime/ScopeChain.cpp index 099f7fde6..e7ea07508 100644 --- a/Source/JavaScriptCore/runtime/ScopeChain.cpp +++ b/Source/JavaScriptCore/runtime/ScopeChain.cpp @@ -42,12 +42,12 @@ void ScopeChainNode::print() o->methodTable()->getPropertyNames(o, globalObject->globalExec(), propertyNames, ExcludeDontEnumProperties); PropertyNameArray::const_iterator propEnd = propertyNames.end(); - fprintf(stderr, "----- [scope %p] -----\n", o); + dataLog("----- [scope %p] -----\n", o); for (PropertyNameArray::const_iterator propIter = propertyNames.begin(); propIter != propEnd; propIter++) { Identifier name = *propIter; - fprintf(stderr, "%s, ", name.ustring().utf8().data()); + dataLog("%s, ", name.ustring().utf8().data()); } - fprintf(stderr, "\n"); + dataLog("\n"); } } diff --git a/Source/JavaScriptCore/runtime/ScopeChain.h b/Source/JavaScriptCore/runtime/ScopeChain.h index 6e358d779..c382008f1 100644 --- a/Source/JavaScriptCore/runtime/ScopeChain.h +++ b/Source/JavaScriptCore/runtime/ScopeChain.h @@ -30,6 +30,7 @@ namespace JSC { class JSGlobalData; class JSGlobalObject; class JSObject; + class LLIntOffsetsExtractor; class ScopeChainIterator; class SlotVisitor; @@ -91,6 +92,8 @@ namespace JSC { static JS_EXPORTDATA const ClassInfo s_info; private: + friend class LLIntOffsetsExtractor; + static const unsigned StructureFlags = OverridesVisitChildren; }; diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp index f387cf283..6ee419da6 100644 --- a/Source/JavaScriptCore/runtime/Structure.cpp +++ b/Source/JavaScriptCore/runtime/Structure.cpp @@ -142,17 +142,17 @@ void Structure::dumpStatistics() } } - printf("Number of live Structures: %d\n", liveStructureSet.size()); - printf("Number of Structures using the single item optimization for transition map: %d\n", numberUsingSingleSlot); - printf("Number of Structures that are leaf nodes: %d\n", numberLeaf); - printf("Number of Structures that singletons: %d\n", numberSingletons); - printf("Number of Structures with PropertyMaps: %d\n", numberWithPropertyMaps); - - printf("Size of a single Structures: %d\n", static_cast<unsigned>(sizeof(Structure))); - printf("Size of sum of all property maps: %d\n", totalPropertyMapsSize); - printf("Size of average of all property maps: %f\n", static_cast<double>(totalPropertyMapsSize) / static_cast<double>(liveStructureSet.size())); + dataLog("Number of live Structures: %d\n", liveStructureSet.size()); + dataLog("Number of Structures using the single item optimization for transition map: %d\n", numberUsingSingleSlot); + dataLog("Number of Structures that are leaf nodes: %d\n", numberLeaf); + dataLog("Number of Structures that singletons: %d\n", numberSingletons); + dataLog("Number of Structures with PropertyMaps: %d\n", numberWithPropertyMaps); + + dataLog("Size of a single Structures: %d\n", static_cast<unsigned>(sizeof(Structure))); + dataLog("Size of sum of all property maps: %d\n", totalPropertyMapsSize); + dataLog("Size of average of all property maps: %f\n", static_cast<double>(totalPropertyMapsSize) / static_cast<double>(liveStructureSet.size())); #else - printf("Dumping Structure statistics is not enabled.\n"); + dataLog("Dumping Structure statistics is not enabled.\n"); #endif } @@ -167,6 +167,7 @@ Structure::Structure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSV , m_dictionaryKind(NoneDictionaryKind) , m_isPinnedPropertyTable(false) , m_hasGetterSetterProperties(false) + , m_hasReadOnlyOrGetterSetterPropertiesExcludingProto(false) , m_hasNonEnumerableProperties(false) , m_attributesInPrevious(0) , m_specificFunctionThrashCount(0) @@ -188,6 +189,7 @@ Structure::Structure(JSGlobalData& globalData) , m_dictionaryKind(NoneDictionaryKind) , m_isPinnedPropertyTable(false) , m_hasGetterSetterProperties(false) + , m_hasReadOnlyOrGetterSetterPropertiesExcludingProto(false) , m_hasNonEnumerableProperties(false) , m_attributesInPrevious(0) , m_specificFunctionThrashCount(0) @@ -207,6 +209,7 @@ Structure::Structure(JSGlobalData& globalData, const Structure* previous) , m_dictionaryKind(previous->m_dictionaryKind) , m_isPinnedPropertyTable(false) , m_hasGetterSetterProperties(previous->m_hasGetterSetterProperties) + , m_hasReadOnlyOrGetterSetterPropertiesExcludingProto(previous->m_hasReadOnlyOrGetterSetterPropertiesExcludingProto) , m_hasNonEnumerableProperties(previous->m_hasNonEnumerableProperties) , m_attributesInPrevious(0) , m_specificFunctionThrashCount(previous->m_specificFunctionThrashCount) @@ -322,7 +325,7 @@ Structure* Structure::addPropertyTransition(JSGlobalData& globalData, Structure* transition->growPropertyStorageCapacity(); return transition; } - + Structure* transition = create(globalData, structure); transition->m_cachedPrototypeChain.setMayBeNull(globalData, transition, structure->m_cachedPrototypeChain.get()); @@ -467,9 +470,12 @@ Structure* Structure::freezeTransition(JSGlobalData& globalData, Structure* stru Structure* transition = preventExtensionsTransition(globalData, structure); if (transition->m_propertyTable) { + PropertyTable::iterator iter = transition->m_propertyTable->begin(); PropertyTable::iterator end = transition->m_propertyTable->end(); - for (PropertyTable::iterator iter = transition->m_propertyTable->begin(); iter != end; ++iter) - iter->attributes |= (DontDelete | ReadOnly); + if (iter != end) + transition->m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true; + for (; iter != end; ++iter) + iter->attributes |= iter->attributes & Accessor ? DontDelete : (DontDelete | ReadOnly); } return transition; @@ -520,7 +526,9 @@ bool Structure::isFrozen(JSGlobalData& globalData) PropertyTable::iterator end = m_propertyTable->end(); for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) { - if ((iter->attributes & (DontDelete | ReadOnly)) != (DontDelete | ReadOnly)) + if (!(iter->attributes & DontDelete)) + return false; + if (!(iter->attributes & (ReadOnly | Accessor))) return false; } return true; @@ -601,11 +609,11 @@ static PropertyMapStatisticsExitLogger logger; PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger() { - printf("\nJSC::PropertyMap statistics\n\n"); - printf("%d probes\n", numProbes); - printf("%d collisions (%.1f%%)\n", numCollisions, 100.0 * numCollisions / numProbes); - printf("%d rehashes\n", numRehashes); - printf("%d removes\n", numRemoves); + dataLog("\nJSC::PropertyMap statistics\n\n"); + dataLog("%d probes\n", numProbes); + dataLog("%d collisions (%.1f%%)\n", numCollisions, 100.0 * numCollisions / numProbes); + dataLog("%d rehashes\n", numRehashes); + dataLog("%d removes\n", numRemoves); } #endif diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h index ced296856..46cf732e1 100644 --- a/Source/JavaScriptCore/runtime/Structure.h +++ b/Source/JavaScriptCore/runtime/Structure.h @@ -45,6 +45,7 @@ namespace JSC { + class LLIntOffsetsExtractor; class PropertyNameArray; class PropertyNameArrayData; class StructureChain; @@ -145,7 +146,17 @@ namespace JSC { } bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; } - void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; } + bool hasReadOnlyOrGetterSetterPropertiesExcludingProto() const { return m_hasReadOnlyOrGetterSetterPropertiesExcludingProto; } + void setHasGetterSetterProperties(bool is__proto__) + { + m_hasGetterSetterProperties = true; + if (!is__proto__) + m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true; + } + void setContainsReadOnlyProperties() + { + m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true; + } bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; } @@ -196,6 +207,8 @@ namespace JSC { static JS_EXPORTDATA const ClassInfo s_info; private: + friend class LLIntOffsetsExtractor; + JS_EXPORT_PRIVATE Structure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*); Structure(JSGlobalData&); Structure(JSGlobalData&, const Structure*); @@ -282,6 +295,7 @@ namespace JSC { unsigned m_dictionaryKind : 2; bool m_isPinnedPropertyTable : 1; bool m_hasGetterSetterProperties : 1; + bool m_hasReadOnlyOrGetterSetterPropertiesExcludingProto : 1; bool m_hasNonEnumerableProperties : 1; unsigned m_attributesInPrevious : 7; unsigned m_specificFunctionThrashCount : 2; diff --git a/Source/JavaScriptCore/runtime/StructureChain.h b/Source/JavaScriptCore/runtime/StructureChain.h index df7a37fa7..3b19d4cf1 100644 --- a/Source/JavaScriptCore/runtime/StructureChain.h +++ b/Source/JavaScriptCore/runtime/StructureChain.h @@ -37,6 +37,7 @@ namespace JSC { + class LLIntOffsetsExtractor; class Structure; class StructureChain : public JSCell { @@ -74,6 +75,8 @@ namespace JSC { } private: + friend class LLIntOffsetsExtractor; + StructureChain(JSGlobalData&, Structure*); static void destroy(JSCell*); OwnArrayPtr<WriteBarrier<Structure> > m_vector; diff --git a/Source/JavaScriptCore/runtime/StructureTransitionTable.h b/Source/JavaScriptCore/runtime/StructureTransitionTable.h index 536237a33..517992470 100644 --- a/Source/JavaScriptCore/runtime/StructureTransitionTable.h +++ b/Source/JavaScriptCore/runtime/StructureTransitionTable.h @@ -29,7 +29,6 @@ #include "UString.h" #include "WeakGCMap.h" #include <wtf/HashFunctions.h> -#include <wtf/HashTraits.h> #include <wtf/OwnPtr.h> #include <wtf/RefPtr.h> @@ -55,22 +54,6 @@ class StructureTransitionTable { static const bool safeToCompareToEmptyOrDeleted = true; }; - struct HashTraits { - typedef WTF::HashTraits<RefPtr<StringImpl> > FirstTraits; - typedef WTF::GenericHashTraits<unsigned> SecondTraits; - typedef std::pair<FirstTraits::TraitType, SecondTraits::TraitType > TraitType; - - static const bool emptyValueIsZero = FirstTraits::emptyValueIsZero && SecondTraits::emptyValueIsZero; - static TraitType emptyValue() { return std::make_pair(FirstTraits::emptyValue(), SecondTraits::emptyValue()); } - - static const bool needsDestruction = FirstTraits::needsDestruction || SecondTraits::needsDestruction; - - static const int minimumTableSize = FirstTraits::minimumTableSize; - - static void constructDeletedValue(TraitType& slot) { FirstTraits::constructDeletedValue(slot.first); } - static bool isDeletedValue(const TraitType& value) { return FirstTraits::isDeletedValue(value.first); } - }; - struct WeakGCMapFinalizerCallback { static void* finalizerContextFor(Hash::Key) { @@ -83,7 +66,7 @@ class StructureTransitionTable { } }; - typedef WeakGCMap<Hash::Key, Structure, WeakGCMapFinalizerCallback, Hash, HashTraits> TransitionMap; + typedef WeakGCMap<Hash::Key, Structure, WeakGCMapFinalizerCallback, Hash> TransitionMap; static Hash::Key keyForWeakGCMapFinalizer(void* context, Structure*); diff --git a/Source/JavaScriptCore/runtime/WriteBarrier.h b/Source/JavaScriptCore/runtime/WriteBarrier.h index 6ac52b7c7..7e9db12fb 100644 --- a/Source/JavaScriptCore/runtime/WriteBarrier.h +++ b/Source/JavaScriptCore/runtime/WriteBarrier.h @@ -26,6 +26,7 @@ #ifndef WriteBarrier_h #define WriteBarrier_h +#include "GCAssertions.h" #include "HandleTypes.h" #include "Heap.h" #include "SamplingCounter.h" @@ -73,6 +74,13 @@ public: validateCell(value); setEarlyValue(globalData, owner, value); } + + // This is meant to be used like operator=, but is called copyFrom instead, in + // order to kindly inform the C++ compiler that its advice is not appreciated. + void copyFrom(const WriteBarrierBase<T>& other) + { + m_cell = other.m_cell; + } void setMayBeNull(JSGlobalData& globalData, const JSCell* owner, T* value) { |