diff options
Diffstat (limited to 'Source/JavaScriptCore/runtime')
38 files changed, 1889 insertions, 1427 deletions
diff --git a/Source/JavaScriptCore/runtime/Arguments.h b/Source/JavaScriptCore/runtime/Arguments.h index 7c8b69bd1..7961d4bc8 100644 --- a/Source/JavaScriptCore/runtime/Arguments.h +++ b/Source/JavaScriptCore/runtime/Arguments.h @@ -267,8 +267,7 @@ namespace JSC { m_overrodeCallee = false; m_overrodeCaller = false; m_isStrictMode = jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->isStrictMode(); - - ASSERT(!jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->symbolTable()->slowArguments()); + ASSERT(!jsCast<FunctionExecutable*>(inlineCallFrame->executable.get())->symbolTable(inlineCallFrame->isCall ? CodeForCall : CodeForConstruct)->slowArguments()); // The bytecode generator omits op_tear_off_activation in cases of no // declared parameters, so we need to tear off immediately. diff --git a/Source/JavaScriptCore/runtime/ArrayConventions.h b/Source/JavaScriptCore/runtime/ArrayConventions.h index a557b1ef9..3177c6c97 100644 --- a/Source/JavaScriptCore/runtime/ArrayConventions.h +++ b/Source/JavaScriptCore/runtime/ArrayConventions.h @@ -58,7 +58,7 @@ namespace JSC { // These values have to be macros to be used in max() and min() without introducing // a PIC branch in Mach-O binaries, see <rdar://problem/5971391>. -#define MIN_SPARSE_ARRAY_INDEX 10000U +#define MIN_SPARSE_ARRAY_INDEX 100000U #define MAX_STORAGE_VECTOR_INDEX (MAX_STORAGE_VECTOR_LENGTH - 1) // 0xFFFFFFFF is a bit weird -- is not an array index even though it's an integer. #define MAX_ARRAY_INDEX 0xFFFFFFFEU diff --git a/Source/JavaScriptCore/runtime/CachedTranscendentalFunction.h b/Source/JavaScriptCore/runtime/CachedTranscendentalFunction.h index f31b4a07f..62a01dbcb 100644 --- a/Source/JavaScriptCore/runtime/CachedTranscendentalFunction.h +++ b/Source/JavaScriptCore/runtime/CachedTranscendentalFunction.h @@ -74,8 +74,8 @@ private: // Lazily allocate the table, populate with NaN->NaN mapping. m_cache = static_cast<CacheEntry*>(fastMalloc(s_cacheSize * sizeof(CacheEntry))); for (unsigned x = 0; x < s_cacheSize; ++x) { - m_cache[x].operand = std::numeric_limits<double>::quiet_NaN(); - m_cache[x].result = std::numeric_limits<double>::quiet_NaN(); + m_cache[x].operand = QNaN; + m_cache[x].result = QNaN; } } diff --git a/Source/JavaScriptCore/runtime/CodeCache.cpp b/Source/JavaScriptCore/runtime/CodeCache.cpp new file mode 100644 index 000000000..4de760e49 --- /dev/null +++ b/Source/JavaScriptCore/runtime/CodeCache.cpp @@ -0,0 +1,186 @@ +/* + * 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. + */ + +#include "config.h" + +#include "CodeCache.h" + +#include "BytecodeGenerator.h" +#include "CodeSpecializationKind.h" +#include "Parser.h" +#include "StrongInlines.h" +#include "UnlinkedCodeBlock.h" + +namespace JSC { + +CodeCache::CodeCache() + : m_randomGenerator(static_cast<uint32_t>(randomNumber() * UINT32_MAX)) +{ +} + +CodeCache::~CodeCache() +{ +} + +CodeCache::CodeBlockKey CodeCache::makeCodeBlockKey(const SourceCode& source, CodeCache::CodeType type, JSParserStrictness strictness) +{ + return std::make_pair(source.toString(), (type << 1) | strictness); +} + +template <typename T> struct CacheTypes { }; + +template <> struct CacheTypes<UnlinkedProgramCodeBlock> { + typedef JSC::ProgramNode RootNode; + static const CodeCache::CodeType codeType = CodeCache::ProgramType; +}; + +template <> struct CacheTypes<UnlinkedEvalCodeBlock> { + typedef JSC::EvalNode RootNode; + static const CodeCache::CodeType codeType = CodeCache::EvalType; +}; + +template <class UnlinkedCodeBlockType, class ExecutableType> +UnlinkedCodeBlockType* CodeCache::getCodeBlock(JSGlobalData& globalData, ExecutableType* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) +{ + CodeBlockKey key = makeCodeBlockKey(source, CacheTypes<UnlinkedCodeBlockType>::codeType, strictness); + bool storeInCache = false; + if (debuggerMode == DebuggerOff && profilerMode == ProfilerOff) { + CodeBlockIndicesMap::iterator result = m_cachedCodeBlockIndices.find(key); + if (result != m_cachedCodeBlockIndices.end()) { + UnlinkedCodeBlockType* unlinkedCode = jsCast<UnlinkedCodeBlockType*>(m_cachedCodeBlocks[result->value].second.get()); + unsigned firstLine = source.firstLine() + unlinkedCode->firstLine(); + executable->recordParse(unlinkedCode->codeFeatures(), unlinkedCode->hasCapturedVariables(), firstLine, firstLine + unlinkedCode->lineCount()); + return unlinkedCode; + } + storeInCache = true; + } + + typedef typename CacheTypes<UnlinkedCodeBlockType>::RootNode RootNode; + RefPtr<RootNode> rootNode = parse<RootNode>(&globalData, source, 0, Identifier(), strictness, JSParseProgramCode, error); + if (!rootNode) + return 0; + executable->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), rootNode->lineNo(), rootNode->lastLine()); + + UnlinkedCodeBlockType* unlinkedCode = UnlinkedCodeBlockType::create(&globalData, executable->executableInfo()); + unlinkedCode->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), rootNode->lineNo() - source.firstLine(), rootNode->lastLine() - rootNode->lineNo()); + OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(globalData, rootNode.get(), unlinkedCode, debuggerMode, profilerMode))); + error = generator->generate(); + rootNode->destroyData(); + if (error.m_type != ParserError::ErrorNone) + return 0; + + if (storeInCache) { + size_t index = m_randomGenerator.getUint32() % kMaxCodeBlockEntries; + if (m_cachedCodeBlocks[index].second) + m_cachedCodeBlockIndices.remove(m_cachedCodeBlocks[index].first); + m_cachedCodeBlockIndices.set(key, index); + m_cachedCodeBlocks[index].second.set(globalData, unlinkedCode); + m_cachedCodeBlocks[index].first = key; + } + + return unlinkedCode; +} + +UnlinkedProgramCodeBlock* CodeCache::getProgramCodeBlock(JSGlobalData& globalData, ProgramExecutable* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) +{ + return getCodeBlock<UnlinkedProgramCodeBlock>(globalData, executable, source, strictness, debuggerMode, profilerMode, error); +} + +UnlinkedEvalCodeBlock* CodeCache::getEvalCodeBlock(JSGlobalData& globalData, EvalExecutable* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) +{ + return getCodeBlock<UnlinkedEvalCodeBlock>(globalData, executable, source, strictness, debuggerMode, profilerMode, error); +} + +UnlinkedFunctionCodeBlock* CodeCache::generateFunctionCodeBlock(JSGlobalData& globalData, UnlinkedFunctionExecutable* executable, const SourceCode& source, CodeSpecializationKind kind, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) +{ + RefPtr<FunctionBodyNode> body = parse<FunctionBodyNode>(&globalData, source, executable->parameters(), executable->name(), executable->isInStrictContext() ? JSParseStrict : JSParseNormal, JSParseFunctionCode, error); + + if (!body) { + ASSERT(error.m_type != ParserError::ErrorNone); + return 0; + } + + if (executable->forceUsesArguments()) + body->setUsesArguments(); + body->finishParsing(executable->parameters(), executable->name(), executable->functionNameIsInScopeToggle()); + executable->recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine()); + + UnlinkedFunctionCodeBlock* result = UnlinkedFunctionCodeBlock::create(&globalData, FunctionCode, ExecutableInfo(body->needsActivation(), body->usesEval(), body->isStrictMode(), kind == CodeForConstruct)); + OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(globalData, body.get(), result, debuggerMode, profilerMode))); + error = generator->generate(); + body->destroyData(); + if (error.m_type != ParserError::ErrorNone) + return 0; + return result; +} + +UnlinkedFunctionCodeBlock* CodeCache::getFunctionCodeBlock(JSGlobalData& globalData, UnlinkedFunctionExecutable* executable, const SourceCode& source, CodeSpecializationKind kind, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) +{ + return generateFunctionCodeBlock(globalData, executable, source, kind, debuggerMode, profilerMode, error); +} + +CodeCache::GlobalFunctionKey CodeCache::makeGlobalFunctionKey(const SourceCode& source, const String& name) +{ + return GlobalFunctionKey(source.toString(), name); +} + +UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(JSGlobalData& globalData, const Identifier& name, const SourceCode& source, ParserError& error) +{ + GlobalFunctionKey key = makeGlobalFunctionKey(source, name.string()); + GlobalFunctionIndicesMap::iterator result = m_cachedGlobalFunctionIndices.find(key); + if (result != m_cachedGlobalFunctionIndices.end()) + return m_cachedGlobalFunctions[result->value].second.get(); + + RefPtr<ProgramNode> program = parse<ProgramNode>(&globalData, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error); + if (!program) { + ASSERT(error.m_type != ParserError::ErrorNone); + return 0; + } + + // This function assumes an input string that would result in a single anonymous function expression. + StatementNode* exprStatement = program->singleStatement(); + ASSERT(exprStatement); + ASSERT(exprStatement->isExprStatement()); + ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr(); + ASSERT(funcExpr); + ASSERT(funcExpr->isFuncExprNode()); + FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body(); + ASSERT(body); + ASSERT(body->ident().isNull()); + + UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&globalData, source, body); + functionExecutable->m_nameValue.set(globalData, functionExecutable, jsString(&globalData, name.string())); + + size_t index = m_randomGenerator.getUint32() % kMaxGlobalFunctionEntries; + if (m_cachedGlobalFunctions[index].second) + m_cachedGlobalFunctionIndices.remove(m_cachedGlobalFunctions[index].first); + m_cachedGlobalFunctionIndices.set(key, index); + m_cachedGlobalFunctions[index].second.set(globalData, functionExecutable); + m_cachedGlobalFunctions[index].first = key; + + return functionExecutable; +} + +} diff --git a/Source/JavaScriptCore/runtime/CodeCache.h b/Source/JavaScriptCore/runtime/CodeCache.h new file mode 100644 index 000000000..4d4617189 --- /dev/null +++ b/Source/JavaScriptCore/runtime/CodeCache.h @@ -0,0 +1,93 @@ +/* + * 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 CodeCache_h +#define CodeCache_h + +#include "CodeSpecializationKind.h" +#include "ParserModes.h" +#include "Strong.h" +#include "WeakRandom.h" + +#include <wtf/FixedArray.h> +#include <wtf/Forward.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/text/WTFString.h> + +namespace JSC { + +class EvalExecutable; +class Identifier; +class ProgramExecutable; +class UnlinkedCodeBlock; +class UnlinkedEvalCodeBlock; +class UnlinkedFunctionCodeBlock; +class UnlinkedFunctionExecutable; +class UnlinkedProgramCodeBlock; +class JSGlobalData; +struct ParserError; +class SourceCode; +class SourceProvider; + +class CodeCache { +public: + static PassOwnPtr<CodeCache> create() { return adoptPtr(new CodeCache); } + + UnlinkedProgramCodeBlock* getProgramCodeBlock(JSGlobalData&, ProgramExecutable*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&); + UnlinkedEvalCodeBlock* getEvalCodeBlock(JSGlobalData&, EvalExecutable*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&); + UnlinkedFunctionCodeBlock* getFunctionCodeBlock(JSGlobalData&, UnlinkedFunctionExecutable*, const SourceCode&, CodeSpecializationKind, DebuggerMode, ProfilerMode, ParserError&); + UnlinkedFunctionExecutable* getFunctionExecutableFromGlobalCode(JSGlobalData&, const Identifier&, const SourceCode&, ParserError&); + ~CodeCache(); + + enum CodeType { EvalType, ProgramType, FunctionType }; + typedef std::pair<String, unsigned> CodeBlockKey; + typedef HashMap<CodeBlockKey, unsigned> CodeBlockIndicesMap; + typedef std::pair<String, String> GlobalFunctionKey; + typedef HashMap<GlobalFunctionKey, unsigned> GlobalFunctionIndicesMap; + +private: + CodeCache(); + + UnlinkedFunctionCodeBlock* generateFunctionCodeBlock(JSGlobalData&, UnlinkedFunctionExecutable*, const SourceCode&, CodeSpecializationKind, DebuggerMode, ProfilerMode, ParserError&); + + template <class UnlinkedCodeBlockType, class ExecutableType> inline UnlinkedCodeBlockType* getCodeBlock(JSGlobalData&, ExecutableType*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&); + CodeBlockKey makeCodeBlockKey(const SourceCode&, CodeType, JSParserStrictness); + CodeBlockIndicesMap m_cachedCodeBlockIndices; + GlobalFunctionKey makeGlobalFunctionKey(const SourceCode&, const String&); + GlobalFunctionIndicesMap m_cachedGlobalFunctionIndices; + + enum { + kMaxCodeBlockEntries = 1024, + kMaxGlobalFunctionEntries = 1024 + }; + + FixedArray<std::pair<CodeBlockKey, Strong<UnlinkedCodeBlock> >, kMaxCodeBlockEntries> m_cachedCodeBlocks; + FixedArray<std::pair<GlobalFunctionKey, Strong<UnlinkedFunctionExecutable> >, kMaxGlobalFunctionEntries> m_cachedGlobalFunctions; + WeakRandom m_randomGenerator; +}; + +} + +#endif diff --git a/Source/JavaScriptCore/runtime/DateConstructor.cpp b/Source/JavaScriptCore/runtime/DateConstructor.cpp index f78e8bf55..9a162e9e7 100644 --- a/Source/JavaScriptCore/runtime/DateConstructor.cpp +++ b/Source/JavaScriptCore/runtime/DateConstructor.cpp @@ -131,7 +131,7 @@ JSObject* constructDate(ExecState* exec, JSGlobalObject* globalObject, const Arg || (numArgs >= 5 && !isfinite(doubleArguments[4])) || (numArgs >= 6 && !isfinite(doubleArguments[5])) || (numArgs >= 7 && !isfinite(doubleArguments[6]))) - value = std::numeric_limits<double>::quiet_NaN(); + value = QNaN; else { GregorianDateTime t; int year = JSC::toInt32(doubleArguments[0]); diff --git a/Source/JavaScriptCore/runtime/DateInstanceCache.h b/Source/JavaScriptCore/runtime/DateInstanceCache.h index 153582f67..e186516e8 100644 --- a/Source/JavaScriptCore/runtime/DateInstanceCache.h +++ b/Source/JavaScriptCore/runtime/DateInstanceCache.h @@ -45,8 +45,8 @@ namespace JSC { private: DateInstanceData() - : m_gregorianDateTimeCachedForMS(std::numeric_limits<double>::quiet_NaN()) - , m_gregorianDateTimeUTCCachedForMS(std::numeric_limits<double>::quiet_NaN()) + : m_gregorianDateTimeCachedForMS(QNaN) + , m_gregorianDateTimeUTCCachedForMS(QNaN) { } }; @@ -61,7 +61,7 @@ namespace JSC { void reset() { for (size_t i = 0; i < cacheSize; ++i) - m_cache[i].key = std::numeric_limits<double>::quiet_NaN(); + m_cache[i].key = QNaN; } DateInstanceData* add(double d) diff --git a/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp b/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp index a3281b6d6..a4368a2bb 100644 --- a/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp +++ b/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp @@ -48,7 +48,7 @@ JSValue InterruptedExecutionError::defaultValue(const JSObject*, ExecState* exec { if (hint == PreferString) return jsNontrivialString(exec, String(ASCIILiteral("JavaScript execution exceeded timeout."))); - return JSValue(std::numeric_limits<double>::quiet_NaN()); + return JSValue(QNaN); } JSObject* createInterruptedExecutionException(JSGlobalData* globalData) @@ -75,7 +75,7 @@ JSValue TerminatedExecutionError::defaultValue(const JSObject*, ExecState* exec, { if (hint == PreferString) return jsNontrivialString(exec, String(ASCIILiteral("JavaScript execution terminated."))); - return JSValue(std::numeric_limits<double>::quiet_NaN()); + return JSValue(QNaN); } JSObject* createTerminatedExecutionException(JSGlobalData* globalData) diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp index 0a453eea0..20a2e2acb 100644 --- a/Source/JavaScriptCore/runtime/Executable.cpp +++ b/Source/JavaScriptCore/runtime/Executable.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "Executable.h" +#include "BatchedTransitionOptimizer.h" #include "BytecodeGenerator.h" #include "CodeBlock.h" #include "DFGDriver.h" @@ -133,16 +134,14 @@ void ProgramExecutable::destroy(JSCell* cell) const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionExecutable) }; -FunctionExecutable::FunctionExecutable(JSGlobalData& globalData, FunctionBodyNode* node) - : ScriptExecutable(globalData.functionExecutableStructure.get(), globalData, node->source(), node->isStrictMode()) - , m_forceUsesArguments(node->usesArguments()) - , m_parameters(node->parameters()) - , m_name(node->ident()) - , m_inferredName(node->inferredName().isNull() ? globalData.propertyNames->emptyIdentifier : node->inferredName()) - , m_functionNameIsInScopeToggle(node->functionNameIsInScopeToggle()) +FunctionExecutable::FunctionExecutable(JSGlobalData& globalData, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, unsigned lastLine) + : ScriptExecutable(globalData.functionExecutableStructure.get(), globalData, source, unlinkedExecutable->isInStrictContext()) + , m_unlinkedExecutable(globalData, this, unlinkedExecutable) { - m_firstLine = node->lineNo(); - m_lastLine = node->lastLine(); + ASSERT(!source.isNull()); + ASSERT(source.length()); + m_firstLine = firstLine; + m_lastLine = lastLine; } void FunctionExecutable::destroy(JSCell* cell) @@ -191,7 +190,6 @@ JSObject* EvalExecutable::compileInternal(ExecState* exec, JSScope* scope, JITCo UNUSED_PARAM(jitType); UNUSED_PARAM(bytecodeIndex); #endif - JSObject* exception = 0; JSGlobalData* globalData = &exec->globalData(); JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); @@ -200,28 +198,21 @@ JSObject* EvalExecutable::compileInternal(ExecState* exec, JSScope* scope, JITCo newCodeBlock->setAlternative(static_pointer_cast<CodeBlock>(m_evalCodeBlock.release())); m_evalCodeBlock = newCodeBlock.release(); } else { + UNUSED_PARAM(scope); + UNUSED_PARAM(globalData); + UNUSED_PARAM(lexicalGlobalObject); if (!lexicalGlobalObject->evalEnabled()) return throwError(exec, createEvalError(exec, lexicalGlobalObject->evalDisabledErrorMessage())); - RefPtr<EvalNode> evalNode = parse<EvalNode>(globalData, lexicalGlobalObject, m_source, 0, Identifier(), isStrictMode() ? JSParseStrict : JSParseNormal, EvalNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception); - if (!evalNode) { - ASSERT(exception); + + JSObject* exception = 0; + UnlinkedEvalCodeBlock* unlinkedEvalCode = lexicalGlobalObject->createEvalCodeBlock(exec, this, &exception); + if (!unlinkedEvalCode) return exception; - } - recordParse(evalNode->features(), evalNode->hasCapturedVariables(), evalNode->lineNo(), evalNode->lastLine()); - - JSGlobalObject* globalObject = scope->globalObject(); - + OwnPtr<CodeBlock> previousCodeBlock = m_evalCodeBlock.release(); ASSERT((jitType == JITCode::bottomTierJIT()) == !previousCodeBlock); - m_evalCodeBlock = adoptPtr(new EvalCodeBlock(this, globalObject, source().provider(), scope->localDepth(), previousCodeBlock.release())); - OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(evalNode.get(), scope, m_evalCodeBlock->symbolTable(), m_evalCodeBlock.get(), !!m_evalCodeBlock->alternative() ? OptimizingCompilation : FirstCompilation))); - if ((exception = generator->generate())) { - m_evalCodeBlock = static_pointer_cast<EvalCodeBlock>(m_evalCodeBlock->releaseAlternative()); - evalNode->destroyData(); - return exception; - } - - evalNode->destroyData(); + m_unlinkedEvalCodeBlock.set(*globalData, this, unlinkedEvalCode); + m_evalCodeBlock = adoptPtr(new EvalCodeBlock(this, unlinkedEvalCode, lexicalGlobalObject, source().provider(), scope->localDepth(), previousCodeBlock.release())); m_evalCodeBlock->copyPostParseDataFromAlternative(); } @@ -257,6 +248,7 @@ void EvalExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) ScriptExecutable::visitChildren(thisObject, visitor); if (thisObject->m_evalCodeBlock) thisObject->m_evalCodeBlock->visitAggregate(visitor); + visitor.append(&thisObject->m_unlinkedEvalCodeBlock); } void EvalExecutable::unlinkCalls() @@ -272,19 +264,20 @@ void EvalExecutable::unlinkCalls() void EvalExecutable::clearCode() { m_evalCodeBlock.clear(); + m_unlinkedEvalCodeBlock.clear(); Base::clearCode(); } JSObject* ProgramExecutable::checkSyntax(ExecState* exec) { - JSObject* exception = 0; + ParserError error; JSGlobalData* globalData = &exec->globalData(); JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); - RefPtr<ProgramNode> programNode = parse<ProgramNode>(globalData, lexicalGlobalObject, m_source, 0, Identifier(), JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception); + RefPtr<ProgramNode> programNode = parse<ProgramNode>(globalData, m_source, 0, Identifier(), JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, error); if (programNode) return 0; - ASSERT(exception); - return exception; + ASSERT(error.m_type != ParserError::ErrorNone); + return error.toErrorObject(lexicalGlobalObject, m_source); } JSObject* ProgramExecutable::compileOptimized(ExecState* exec, JSScope* scope, unsigned bytecodeIndex) @@ -310,38 +303,17 @@ JSObject* ProgramExecutable::compileInternal(ExecState* exec, JSScope* scope, JI SamplingRegion samplingRegion(samplingDescription(jitType)); #if !ENABLE(JIT) + UNUSED_PARAM(exec); UNUSED_PARAM(jitType); UNUSED_PARAM(bytecodeIndex); #endif - JSObject* exception = 0; - JSGlobalData* globalData = &exec->globalData(); - JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); - if (!!m_programCodeBlock) { OwnPtr<ProgramCodeBlock> newCodeBlock = adoptPtr(new ProgramCodeBlock(CodeBlock::CopyParsedBlock, *m_programCodeBlock)); newCodeBlock->setAlternative(static_pointer_cast<CodeBlock>(m_programCodeBlock.release())); m_programCodeBlock = newCodeBlock.release(); } else { - RefPtr<ProgramNode> programNode = parse<ProgramNode>(globalData, lexicalGlobalObject, m_source, 0, Identifier(), isStrictMode() ? JSParseStrict : JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception); - if (!programNode) { - ASSERT(exception); - return exception; - } - recordParse(programNode->features(), programNode->hasCapturedVariables(), programNode->lineNo(), programNode->lastLine()); - JSGlobalObject* globalObject = scope->globalObject(); - - OwnPtr<CodeBlock> previousCodeBlock = m_programCodeBlock.release(); - ASSERT((jitType == JITCode::bottomTierJIT()) == !previousCodeBlock); - m_programCodeBlock = adoptPtr(new ProgramCodeBlock(this, GlobalCode, globalObject, source().provider(), previousCodeBlock.release())); - OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(programNode.get(), scope, globalObject->symbolTable(), m_programCodeBlock.get(), !!m_programCodeBlock->alternative() ? OptimizingCompilation : FirstCompilation))); - if ((exception = generator->generate())) { - m_programCodeBlock = static_pointer_cast<ProgramCodeBlock>(m_programCodeBlock->releaseAlternative()); - programNode->destroyData(); - return exception; - } - - programNode->destroyData(); + m_programCodeBlock = adoptPtr(new ProgramCodeBlock(this, m_unlinkedProgramCodeBlock.get(), globalObject, source().provider(), m_programCodeBlock.release())); m_programCodeBlock->copyPostParseDataFromAlternative(); } @@ -378,6 +350,67 @@ void ProgramExecutable::unlinkCalls() #endif } +int ProgramExecutable::addGlobalVar(JSGlobalObject* globalObject, const Identifier& ident, ConstantMode constantMode, FunctionMode functionMode) +{ + // Try to share the symbolTable if possible + SharedSymbolTable* symbolTable = globalObject->symbolTable(); + UNUSED_PARAM(functionMode); + int index = symbolTable->size(); + SymbolTableEntry newEntry(index, (constantMode == IsConstant) ? ReadOnly : 0); + if (functionMode == IsFunctionToSpecialize) + newEntry.attemptToWatch(); + SymbolTable::AddResult result = symbolTable->add(ident.impl(), newEntry); + if (!result.isNewEntry) { + result.iterator->value.notifyWrite(); + index = result.iterator->value.getIndex(); + } + return index; +} + +JSObject* ProgramExecutable::initalizeGlobalProperties(JSGlobalData& globalData, CallFrame* callFrame, JSScope* scope) +{ + ASSERT(scope); + JSGlobalObject* globalObject = scope->globalObject(); + ASSERT(globalObject); + ASSERT(&globalObject->globalData() == &globalData); + + JSObject* exception = 0; + UnlinkedProgramCodeBlock* unlinkedCode = globalObject->createProgramCodeBlock(callFrame, this, &exception); + if (exception) + return exception; + + m_unlinkedProgramCodeBlock.set(globalData, this, unlinkedCode); + + BatchedTransitionOptimizer optimizer(globalData, globalObject); + + const UnlinkedProgramCodeBlock::VariableDeclations& variableDeclarations = unlinkedCode->variableDeclarations(); + const UnlinkedProgramCodeBlock::FunctionDeclations& functionDeclarations = unlinkedCode->functionDeclarations(); + + size_t newGlobals = variableDeclarations.size() + functionDeclarations.size(); + if (!newGlobals) + return 0; + globalObject->addRegisters(newGlobals); + CallFrame* globalExec = globalObject->globalExec(); + + for (size_t i = 0; i < functionDeclarations.size(); ++i) { + bool propertyDidExist = globalObject->removeDirect(globalData, functionDeclarations[i].first); // Newly declared functions overwrite existing properties. + UnlinkedFunctionExecutable* unlinkedFunctionExecutable = functionDeclarations[i].second.get(); + JSValue value = JSFunction::create(globalExec, unlinkedFunctionExecutable->link(globalData, m_source, lineNo(), 0), scope); + int index = addGlobalVar(globalObject, functionDeclarations[i].first, IsVariable, + !propertyDidExist ? IsFunctionToSpecialize : NotFunctionOrNotSpecializable); + globalObject->registerAt(index).set(globalData, globalObject, value); + } + + for (size_t i = 0; i < variableDeclarations.size(); ++i) { + if (globalObject->hasProperty(globalExec, variableDeclarations[i].first)) + continue; + addGlobalVar(globalObject, variableDeclarations[i].first, + (variableDeclarations[i].second & DeclarationStacks::IsConstant) ? IsConstant : IsVariable, + NotFunctionOrNotSpecializable); + } + return 0; +} + void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) { ProgramExecutable* thisObject = jsCast<ProgramExecutable*>(cell); @@ -385,6 +418,7 @@ void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); ScriptExecutable::visitChildren(thisObject, visitor); + visitor.append(&thisObject->m_unlinkedProgramCodeBlock); if (thisObject->m_programCodeBlock) thisObject->m_programCodeBlock->visitAggregate(visitor); } @@ -392,6 +426,7 @@ void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) void ProgramExecutable::clearCode() { m_programCodeBlock.clear(); + m_unlinkedProgramCodeBlock.clear(); Base::clearCode(); } @@ -438,12 +473,12 @@ JSObject* FunctionExecutable::compileOptimizedForConstruct(ExecState* exec, JSSc #if ENABLE(JIT) bool FunctionExecutable::jitCompileForCall(ExecState* exec) { - return jitCompileFunctionIfAppropriate(exec, m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, m_symbolTable, JITCode::bottomTierJIT(), UINT_MAX, JITCompilationCanFail); + return jitCompileFunctionIfAppropriate(exec, m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, JITCode::bottomTierJIT(), UINT_MAX, JITCompilationCanFail); } bool FunctionExecutable::jitCompileForConstruct(ExecState* exec) { - return jitCompileFunctionIfAppropriate(exec, m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, m_symbolTable, JITCode::bottomTierJIT(), UINT_MAX, JITCompilationCanFail); + return jitCompileFunctionIfAppropriate(exec, m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, JITCode::bottomTierJIT(), UINT_MAX, JITCompilationCanFail); } #endif @@ -452,49 +487,30 @@ FunctionCodeBlock* FunctionExecutable::codeBlockWithBytecodeFor(CodeSpecializati return baselineCodeBlockFor(kind); } -PassOwnPtr<FunctionCodeBlock> FunctionExecutable::produceCodeBlockFor(JSScope* scope, CompilationKind compilationKind, CodeSpecializationKind specializationKind, JSObject*& exception) +PassOwnPtr<FunctionCodeBlock> FunctionExecutable::produceCodeBlockFor(JSScope* scope, CodeSpecializationKind specializationKind, JSObject*& exception) { if (!!codeBlockFor(specializationKind)) return adoptPtr(new FunctionCodeBlock(CodeBlock::CopyParsedBlock, *codeBlockFor(specializationKind))); - - exception = 0; + JSGlobalData* globalData = scope->globalData(); JSGlobalObject* globalObject = scope->globalObject(); - RefPtr<FunctionBodyNode> body = parse<FunctionBodyNode>( - globalData, - globalObject, - m_source, - m_parameters.get(), - name(), - isStrictMode() ? JSParseStrict : JSParseNormal, - FunctionBodyNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, - 0, - 0, - &exception - ); - - if (!body) { - ASSERT(exception); + ParserError error; + DebuggerMode debuggerMode = globalObject->hasDebugger() ? DebuggerOn : DebuggerOff; + ProfilerMode profilerMode = globalObject->hasProfiler() ? ProfilerOn : ProfilerOff; + UnlinkedFunctionCodeBlock* unlinkedCodeBlock = m_unlinkedExecutable->codeBlockFor(*globalData, m_source, specializationKind, debuggerMode, profilerMode, error); + recordParse(m_unlinkedExecutable->features(), m_unlinkedExecutable->hasCapturedVariables(), lineNo(), lastLine()); + + if (!unlinkedCodeBlock) { + exception = error.toErrorObject(globalObject, m_source); return nullptr; } - if (m_forceUsesArguments) - body->setUsesArguments(); - body->finishParsing(m_parameters, m_name, m_functionNameIsInScopeToggle); - recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine()); - - OwnPtr<FunctionCodeBlock> result; - ASSERT((compilationKind == FirstCompilation) == !codeBlockFor(specializationKind)); - result = adoptPtr(new FunctionCodeBlock(this, FunctionCode, globalObject, source().provider(), source().startOffset(), specializationKind == CodeForConstruct)); - OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(body.get(), scope, result->symbolTable(), result.get(), compilationKind))); - exception = generator->generate(); - body->destroyData(); - if (exception) - return nullptr; + OwnPtr<FunctionCodeBlock> result = adoptPtr(new FunctionCodeBlock(this, unlinkedCodeBlock, globalObject, source().provider(), source().startOffset())); result->copyPostParseDataFrom(codeBlockFor(specializationKind).get()); return result.release(); } + JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, JSScope* scope, JITCode::JITType jitType, unsigned bytecodeIndex) { SamplingRegion samplingRegion(samplingDescription(jitType)); @@ -507,7 +523,7 @@ JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, JSScope* s #endif ASSERT((jitType == JITCode::bottomTierJIT()) == !m_codeBlockForCall); JSObject* exception; - OwnPtr<FunctionCodeBlock> newCodeBlock = produceCodeBlockFor(scope, !!m_codeBlockForCall ? OptimizingCompilation : FirstCompilation, CodeForCall, exception); + OwnPtr<FunctionCodeBlock> newCodeBlock = produceCodeBlockFor(scope, CodeForCall, exception); if (!newCodeBlock) return exception; @@ -516,10 +532,9 @@ JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, JSScope* s m_numParametersForCall = m_codeBlockForCall->numParameters(); ASSERT(m_numParametersForCall); - m_symbolTable.set(exec->globalData(), this, m_codeBlockForCall->symbolTable()); #if ENABLE(JIT) - if (!prepareFunctionForExecution(exec, m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, m_symbolTable, jitType, bytecodeIndex, CodeForCall)) + if (!prepareFunctionForExecution(exec, m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, jitType, bytecodeIndex, CodeForCall)) return 0; #endif @@ -544,7 +559,7 @@ JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, JSSco ASSERT((jitType == JITCode::bottomTierJIT()) == !m_codeBlockForConstruct); JSObject* exception; - OwnPtr<FunctionCodeBlock> newCodeBlock = produceCodeBlockFor(scope, !!m_codeBlockForConstruct ? OptimizingCompilation : FirstCompilation, CodeForConstruct, exception); + OwnPtr<FunctionCodeBlock> newCodeBlock = produceCodeBlockFor(scope, CodeForConstruct, exception); if (!newCodeBlock) return exception; @@ -553,10 +568,9 @@ JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, JSSco m_numParametersForConstruct = m_codeBlockForConstruct->numParameters(); ASSERT(m_numParametersForConstruct); - m_symbolTable.set(exec->globalData(), this, m_codeBlockForConstruct->symbolTable()); #if ENABLE(JIT) - if (!prepareFunctionForExecution(exec, m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, m_symbolTable, jitType, bytecodeIndex, CodeForConstruct)) + if (!prepareFunctionForExecution(exec, m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, jitType, bytecodeIndex, CodeForConstruct)) return 0; #endif @@ -592,12 +606,11 @@ void FunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); ScriptExecutable::visitChildren(thisObject, visitor); - visitor.append(&thisObject->m_nameValue); - visitor.append(&thisObject->m_symbolTable); if (thisObject->m_codeBlockForCall) thisObject->m_codeBlockForCall->visitAggregate(visitor); if (thisObject->m_codeBlockForConstruct) thisObject->m_codeBlockForConstruct->visitAggregate(visitor); + visitor.append(&thisObject->m_unlinkedExecutable); } void FunctionExecutable::clearCodeIfNotCompiling() @@ -607,10 +620,18 @@ void FunctionExecutable::clearCodeIfNotCompiling() clearCode(); } +void FunctionExecutable::clearUnlinkedCodeIfNotCompiling() +{ + if (isCompiling()) + return; + m_unlinkedExecutable->clearCode(); +} + void FunctionExecutable::clearCode() { m_codeBlockForCall.clear(); m_codeBlockForConstruct.clear(); + m_unlinkedExecutable->clearCode(); Base::clearCode(); } @@ -630,39 +651,19 @@ void FunctionExecutable::unlinkCalls() FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& name, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception) { - JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); - RefPtr<ProgramNode> program = parse<ProgramNode>(&exec->globalData(), lexicalGlobalObject, source, 0, Identifier(), JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, debugger, exec, exception); - if (!program) { - ASSERT(*exception); + UnlinkedFunctionExecutable* unlinkedFunction = UnlinkedFunctionExecutable::fromGlobalCode(name, exec, debugger, source, exception); + if (!unlinkedFunction) return 0; - } - - // This function assumes an input string that would result in a single anonymous function expression. - StatementNode* exprStatement = program->singleStatement(); - ASSERT(exprStatement); - ASSERT(exprStatement->isExprStatement()); - ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr(); - ASSERT(funcExpr); - ASSERT(funcExpr->isFuncExprNode()); - FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body(); - ASSERT(body); - ASSERT(body->ident().isNull()); - - FunctionExecutable* functionExecutable = FunctionExecutable::create(exec->globalData(), body); - functionExecutable->m_nameValue.set(exec->globalData(), functionExecutable, jsString(&exec->globalData(), name.string())); - return functionExecutable; + unsigned firstLine = source.firstLine() + unlinkedFunction->firstLineOffset(); + unsigned startOffset = source.startOffset() + unlinkedFunction->startOffset(); + unsigned sourceLength = unlinkedFunction->sourceLength(); + SourceCode functionSource(source.provider(), startOffset, startOffset + sourceLength, firstLine); + return FunctionExecutable::create(exec->globalData(), functionSource, unlinkedFunction, firstLine, unlinkedFunction->lineCount()); } String FunctionExecutable::paramString() const { - FunctionParameters& parameters = *m_parameters; - StringBuilder builder; - for (size_t pos = 0; pos < parameters.size(); ++pos) { - if (!builder.isEmpty()) - builder.appendLiteral(", "); - builder.append(parameters[pos].string()); - } - return builder.toString(); + return m_unlinkedExecutable->paramString(); } } diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h index 76a537da3..74b4add75 100644 --- a/Source/JavaScriptCore/runtime/Executable.h +++ b/Source/JavaScriptCore/runtime/Executable.h @@ -35,6 +35,7 @@ #include "LLIntCLoop.h" #include "Nodes.h" #include "SamplingTool.h" +#include "UnlinkedCodeBlock.h" #include <wtf/PassOwnPtr.h> namespace JSC { @@ -364,9 +365,19 @@ namespace JSC { bool isStrictMode() const { return m_features & StrictModeFeature; } void unlinkCalls(); + + CodeFeatures features() const { return m_features; } static const ClassInfo s_info; + void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine) + { + m_features = features; + m_hasCapturedVariables = hasCapturedVariables; + m_firstLine = firstLine; + m_lastLine = lastLine; + } + protected: void finishCreation(JSGlobalData& globalData) { @@ -379,14 +390,6 @@ namespace JSC { #endif } - void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine) - { - m_features = features; - m_hasCapturedVariables = hasCapturedVariables; - m_firstLine = firstLine; - m_lastLine = lastLine; - } - SourceCode m_source; CodeFeatures m_features; bool m_hasCapturedVariables; @@ -448,6 +451,8 @@ namespace JSC { void clearCode(); + ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false); } + private: static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags; EvalExecutable(ExecState*, const SourceCode&, bool); @@ -456,6 +461,7 @@ namespace JSC { static void visitChildren(JSCell*, SlotVisitor&); OwnPtr<EvalCodeBlock> m_evalCodeBlock; + WriteBarrier<UnlinkedEvalCodeBlock> m_unlinkedEvalCodeBlock; }; class ProgramExecutable : public ScriptExecutable { @@ -470,6 +476,9 @@ namespace JSC { return executable; } + + JSObject* initalizeGlobalProperties(JSGlobalData&, CallFrame*, JSScope*); + static void destroy(JSCell*); JSObject* compile(ExecState* exec, JSScope* scope) @@ -515,13 +524,21 @@ namespace JSC { void clearCode(); + ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false); } + private: static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags; + ProgramExecutable(ExecState*, const SourceCode&); + enum ConstantMode { IsConstant, IsVariable }; + enum FunctionMode { IsFunctionToSpecialize, NotFunctionOrNotSpecializable }; + int addGlobalVar(JSGlobalObject*, const Identifier&, ConstantMode, FunctionMode); + JSObject* compileInternal(ExecState*, JSScope*, JITCode::JITType, unsigned bytecodeIndex = UINT_MAX); static void visitChildren(JSCell*, SlotVisitor&); + WriteBarrier<UnlinkedProgramCodeBlock> m_unlinkedProgramCodeBlock; OwnPtr<ProgramCodeBlock> m_programCodeBlock; }; @@ -531,9 +548,9 @@ namespace JSC { public: typedef ScriptExecutable Base; - static FunctionExecutable* create(JSGlobalData& globalData, FunctionBodyNode* node) + static FunctionExecutable* create(JSGlobalData& globalData, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, unsigned lastLine) { - FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(globalData.heap)) FunctionExecutable(globalData, node); + FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(globalData.heap)) FunctionExecutable(globalData, source, unlinkedExecutable, firstLine, lastLine); executable->finishCreation(globalData); return executable; } @@ -554,7 +571,7 @@ namespace JSC { FunctionCodeBlock* codeBlockWithBytecodeFor(CodeSpecializationKind); - PassOwnPtr<FunctionCodeBlock> produceCodeBlockFor(JSScope*, CompilationKind, CodeSpecializationKind, JSObject*& exception); + PassOwnPtr<FunctionCodeBlock> produceCodeBlockFor(JSScope*, CodeSpecializationKind, JSObject*& exception); JSObject* compileForCall(ExecState* exec, JSScope* scope) { @@ -679,14 +696,15 @@ namespace JSC { return baselineCodeBlockFor(kind); } - const Identifier& name() { return m_name; } - const Identifier& inferredName() { return m_inferredName; } - JSString* nameValue() const { return m_nameValue.get(); } - size_t parameterCount() const { return m_parameters->size(); } // Excluding 'this'! + const Identifier& name() { return m_unlinkedExecutable->name(); } + const Identifier& inferredName() { return m_unlinkedExecutable->inferredName(); } + JSString* nameValue() const { return m_unlinkedExecutable->nameValue(); } + size_t parameterCount() const { return m_unlinkedExecutable->parameterCount(); } // Excluding 'this'! String paramString() const; - SharedSymbolTable* symbolTable() const { return m_symbolTable.get(); } + SharedSymbolTable* symbolTable(CodeSpecializationKind kind) const { return m_unlinkedExecutable->symbolTable(kind); } void clearCodeIfNotCompiling(); + void clearUnlinkedCodeIfNotCompiling(); static void visitChildren(JSCell*, SlotVisitor&); static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { @@ -699,15 +717,8 @@ namespace JSC { void clearCode(); - protected: - void finishCreation(JSGlobalData& globalData) - { - Base::finishCreation(globalData); - m_nameValue.set(globalData, this, jsString(&globalData, name().string())); - } - private: - FunctionExecutable(JSGlobalData&, FunctionBodyNode*); + FunctionExecutable(JSGlobalData&, const SourceCode&, UnlinkedFunctionExecutable*, unsigned firstLine, unsigned lastLine); JSObject* compileForCallInternal(ExecState*, JSScope*, JITCode::JITType, unsigned bytecodeIndex = UINT_MAX); JSObject* compileForConstructInternal(ExecState*, JSScope*, JITCode::JITType, unsigned bytecodeIndex = UINT_MAX); @@ -732,16 +743,9 @@ namespace JSC { } static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags; - bool m_forceUsesArguments; - - RefPtr<FunctionParameters> m_parameters; + WriteBarrier<UnlinkedFunctionExecutable> m_unlinkedExecutable; OwnPtr<FunctionCodeBlock> m_codeBlockForCall; OwnPtr<FunctionCodeBlock> m_codeBlockForConstruct; - Identifier m_name; - Identifier m_inferredName; - FunctionNameIsInScopeToggle m_functionNameIsInScopeToggle; - WriteBarrier<JSString> m_nameValue; - WriteBarrier<SharedSymbolTable> m_symbolTable; }; inline JSFunction::JSFunction(JSGlobalData& globalData, FunctionExecutable* executable, JSScope* scope) diff --git a/Source/JavaScriptCore/runtime/ExecutionHarness.h b/Source/JavaScriptCore/runtime/ExecutionHarness.h index 065788aee..b71b60217 100644 --- a/Source/JavaScriptCore/runtime/ExecutionHarness.h +++ b/Source/JavaScriptCore/runtime/ExecutionHarness.h @@ -49,7 +49,7 @@ inline bool prepareForExecution(ExecState* exec, OwnPtr<CodeBlockType>& codeBloc return jitCompileIfAppropriate(exec, codeBlock, jitCode, jitType, bytecodeIndex, JITCode::isBaselineCode(jitType) ? JITCompilationMustSucceed : JITCompilationCanFail); } -inline bool prepareFunctionForExecution(ExecState* exec, OwnPtr<FunctionCodeBlock>& codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck, WriteBarrier<SharedSymbolTable>& symbolTable, JITCode::JITType jitType, unsigned bytecodeIndex, CodeSpecializationKind kind) +inline bool prepareFunctionForExecution(ExecState* exec, OwnPtr<FunctionCodeBlock>& codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck, JITCode::JITType jitType, unsigned bytecodeIndex, CodeSpecializationKind kind) { #if ENABLE(LLINT) if (JITCode::isBaselineCode(jitType)) { @@ -61,7 +61,7 @@ inline bool prepareFunctionForExecution(ExecState* exec, OwnPtr<FunctionCodeBloc #else UNUSED_PARAM(kind); #endif // ENABLE(LLINT) - return jitCompileFunctionIfAppropriate(exec, codeBlock, jitCode, jitCodeWithArityCheck, symbolTable, jitType, bytecodeIndex, JITCode::isBaselineCode(jitType) ? JITCompilationMustSucceed : JITCompilationCanFail); + return jitCompileFunctionIfAppropriate(exec, codeBlock, jitCode, jitCodeWithArityCheck, jitType, bytecodeIndex, JITCode::isBaselineCode(jitType) ? JITCompilationMustSucceed : JITCompilationCanFail); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Identifier.cpp b/Source/JavaScriptCore/runtime/Identifier.cpp index 45dd0bbde..583c12bb1 100644 --- a/Source/JavaScriptCore/runtime/Identifier.cpp +++ b/Source/JavaScriptCore/runtime/Identifier.cpp @@ -128,7 +128,7 @@ PassRefPtr<StringImpl> Identifier::add8(JSGlobalData* globalData, const UChar* s if (!length) return StringImpl::empty(); - CharBuffer<UChar> buf = {s, length}; + CharBuffer<UChar> buf = { s, static_cast<unsigned>(length) }; HashSet<StringImpl*>::AddResult addResult = globalData->identifierTable->add<CharBuffer<UChar>, IdentifierLCharFromUCharTranslator >(buf); // If the string is newly-translated, then we need to adopt it. diff --git a/Source/JavaScriptCore/runtime/Identifier.h b/Source/JavaScriptCore/runtime/Identifier.h index bdcfbd187..dcb739ec3 100644 --- a/Source/JavaScriptCore/runtime/Identifier.h +++ b/Source/JavaScriptCore/runtime/Identifier.h @@ -180,7 +180,7 @@ namespace JSC { if (!length) return StringImpl::empty(); - CharBuffer<T> buf = {s, length}; + CharBuffer<T> buf = { s, static_cast<unsigned>(length) }; HashSet<StringImpl*>::AddResult addResult = globalData->identifierTable->add<CharBuffer<T>, IdentifierCharBufferTranslator<T> >(buf); // If the string is newly-translated, then we need to adopt it. diff --git a/Source/JavaScriptCore/runtime/JSActivation.h b/Source/JavaScriptCore/runtime/JSActivation.h index fa2291813..fc6336463 100644 --- a/Source/JavaScriptCore/runtime/JSActivation.h +++ b/Source/JavaScriptCore/runtime/JSActivation.h @@ -46,15 +46,16 @@ namespace JSC { public: typedef JSVariableObject Base; - static JSActivation* create(JSGlobalData& globalData, CallFrame* callFrame, FunctionExecutable* functionExecutable) + static JSActivation* create(JSGlobalData& globalData, CallFrame* callFrame, CodeBlock* codeBlock) { + SharedSymbolTable* symbolTable = codeBlock->symbolTable(); JSActivation* activation = new ( NotNull, allocateCell<JSActivation>( globalData.heap, - allocationSize(functionExecutable->symbolTable()) + allocationSize(symbolTable) ) - ) JSActivation(globalData, callFrame, functionExecutable->symbolTable()); + ) JSActivation(globalData, callFrame, symbolTable); activation->finishCreation(globalData); return activation; } diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp index 7028c3b95..d1ece1a36 100644 --- a/Source/JavaScriptCore/runtime/JSArray.cpp +++ b/Source/JavaScriptCore/runtime/JSArray.cpp @@ -1092,7 +1092,7 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call for (; numDefined < usedVectorLength; ++numDefined) { if (numDefined > m_butterfly->vectorLength()) break; - JSValue v = indexingData<indexingType>()[numDefined].get(); + JSValue v = currentIndexingData()[numDefined].get(); if (!v || v.isUndefined()) break; tree.abstractor().m_nodes[numDefined].value = v; @@ -1101,7 +1101,7 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call for (unsigned i = numDefined; i < usedVectorLength; ++i) { if (i > m_butterfly->vectorLength()) break; - JSValue v = indexingData<indexingType>()[i].get(); + JSValue v = currentIndexingData()[i].get(); if (v) { if (v.isUndefined()) ++numUndefined; @@ -1116,7 +1116,7 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call unsigned newUsedVectorLength = numDefined + numUndefined; // The array size may have changed. Figure out the new bounds. - unsigned newestUsedVectorLength = relevantLength<indexingType>(); + unsigned newestUsedVectorLength = currentRelevantLength(); unsigned elementsToExtractThreshold = min(min(newestUsedVectorLength, numDefined), static_cast<unsigned>(tree.abstractor().m_nodes.size())); unsigned undefinedElementsThreshold = min(newestUsedVectorLength, newUsedVectorLength); @@ -1127,18 +1127,18 @@ void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType call iter.start_iter_least(tree); JSGlobalData& globalData = exec->globalData(); for (unsigned i = 0; i < elementsToExtractThreshold; ++i) { - indexingData<indexingType>()[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value); + currentIndexingData()[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value); ++iter; } // Put undefined values back in. for (unsigned i = elementsToExtractThreshold; i < undefinedElementsThreshold; ++i) - indexingData<indexingType>()[i].setUndefined(); + currentIndexingData()[i].setUndefined(); // Ensure that unused values in the vector are zeroed out. for (unsigned i = undefinedElementsThreshold; i < clearElementsThreshold; ++i) - indexingData<indexingType>()[i].clear(); + currentIndexingData()[i].clear(); - if (hasArrayStorage(indexingType)) + if (hasArrayStorage(structure()->indexingType())) arrayStorage()->m_numValuesInVector = newUsedVectorLength; } diff --git a/Source/JavaScriptCore/runtime/JSArray.h b/Source/JavaScriptCore/runtime/JSArray.h index d4622aacc..1d1e64173 100644 --- a/Source/JavaScriptCore/runtime/JSArray.h +++ b/Source/JavaScriptCore/runtime/JSArray.h @@ -27,273 +27,273 @@ namespace JSC { - class JSArray; - class LLIntOffsetsExtractor; +class JSArray; +class LLIntOffsetsExtractor; - class JSArray : public JSNonFinalObject { - friend class LLIntOffsetsExtractor; - friend class Walker; - friend class JIT; +class JSArray : public JSNonFinalObject { + friend class LLIntOffsetsExtractor; + friend class Walker; + friend class JIT; - public: - typedef JSNonFinalObject Base; +public: + typedef JSNonFinalObject Base; - protected: - explicit JSArray(JSGlobalData& globalData, Structure* structure, Butterfly* butterfly) - : JSNonFinalObject(globalData, structure, butterfly) - { - } +protected: + explicit JSArray(JSGlobalData& globalData, Structure* structure, Butterfly* butterfly) + : JSNonFinalObject(globalData, structure, butterfly) + { + } - public: - static JSArray* create(JSGlobalData&, Structure*, unsigned initialLength = 0); +public: + 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. - static JSArray* tryCreateUninitialized(JSGlobalData&, Structure*, unsigned initialLength); + // 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. + static JSArray* tryCreateUninitialized(JSGlobalData&, Structure*, unsigned initialLength); - JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool throwException); + JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool throwException); - static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); - static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); + static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); + static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); - static JS_EXPORTDATA const ClassInfo s_info; + static JS_EXPORTDATA const ClassInfo s_info; - unsigned length() const { return getArrayLength(); } - // OK to use on new arrays, but not if it might be a RegExpMatchArray. - bool setLength(ExecState*, unsigned, bool throwException = false); + unsigned length() const { return getArrayLength(); } + // OK to use on new arrays, but not if it might be a RegExpMatchArray. + bool setLength(ExecState*, unsigned, bool throwException = false); - void sort(ExecState*); - void sort(ExecState*, JSValue compareFunction, CallType, const CallData&); - void sortNumeric(ExecState*, JSValue compareFunction, CallType, const CallData&); + void sort(ExecState*); + void sort(ExecState*, JSValue compareFunction, CallType, const CallData&); + void sortNumeric(ExecState*, JSValue compareFunction, CallType, const CallData&); - void push(ExecState*, JSValue); - JSValue pop(ExecState*); + void push(ExecState*, JSValue); + JSValue pop(ExecState*); - enum ShiftCountMode { - // This form of shift hints that we're doing queueing. With this assumption in hand, - // we convert to ArrayStorage, which has queue optimizations. - ShiftCountForShift, + enum ShiftCountMode { + // This form of shift hints that we're doing queueing. With this assumption in hand, + // we convert to ArrayStorage, which has queue optimizations. + ShiftCountForShift, - // This form of shift hints that we're just doing care and feeding on an array that - // is probably typically used for ordinary accesses. With this assumption in hand, - // we try to preserve whatever indexing type it has already. - ShiftCountForSplice - }; - - bool shiftCountForShift(ExecState* exec, unsigned startIndex, unsigned count) - { - return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData())); - } - bool shiftCountForSplice(ExecState* exec, unsigned startIndex, unsigned count) - { - return shiftCountWithAnyIndexingType(exec, startIndex, count); - } - template<ShiftCountMode shiftCountMode> - bool shiftCount(ExecState* exec, unsigned startIndex, unsigned count) - { - switch (shiftCountMode) { - case ShiftCountForShift: - return shiftCountForShift(exec, startIndex, count); - case ShiftCountForSplice: - return shiftCountForSplice(exec, startIndex, count); - default: - CRASH(); - return false; - } - } - - bool unshiftCountForShift(ExecState* exec, unsigned startIndex, unsigned count) - { - return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData())); - } - bool unshiftCountForSplice(ExecState* exec, unsigned startIndex, unsigned count) - { - return unshiftCountWithAnyIndexingType(exec, startIndex, count); - } - template<ShiftCountMode shiftCountMode> - bool unshiftCount(ExecState* exec, unsigned startIndex, unsigned count) - { - switch (shiftCountMode) { - case ShiftCountForShift: - return unshiftCountForShift(exec, startIndex, count); - case ShiftCountForSplice: - return unshiftCountForSplice(exec, startIndex, count); - default: - CRASH(); - return false; - } - } - - void fillArgList(ExecState*, MarkedArgumentBuffer&); - void copyToArguments(ExecState*, CallFrame*, uint32_t length); - - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, IndexingType indexingType) - { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info, indexingType); - } - - protected: - static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSObject::StructureFlags; - static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); - - static bool deleteProperty(JSCell*, ExecState*, PropertyName); - JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - - private: - bool isLengthWritable() - { - ArrayStorage* storage = arrayStorageOrNull(); - if (!storage) - return true; - SparseArrayValueMap* map = storage->m_sparseMap.get(); - return !map || !map->lengthIsReadOnly(); - } - - bool shiftCountWithAnyIndexingType(ExecState*, unsigned startIndex, unsigned count); - bool shiftCountWithArrayStorage(unsigned startIndex, unsigned count, ArrayStorage*); - - bool unshiftCountWithAnyIndexingType(ExecState*, unsigned startIndex, unsigned count); - bool unshiftCountWithArrayStorage(ExecState*, unsigned startIndex, unsigned count, ArrayStorage*); - bool unshiftCountSlowCase(JSGlobalData&, bool, unsigned); - - template<IndexingType indexingType> - void sortNumericVector(ExecState*, JSValue compareFunction, CallType, const CallData&); - - template<IndexingType indexingType> - void sortCompactedVector(ExecState*, WriteBarrier<Unknown>* begin, unsigned relevantLength); - - template<IndexingType indexingType> - void sortVector(ExecState*, JSValue compareFunction, CallType, const CallData&); - - bool setLengthWithArrayStorage(ExecState*, unsigned newLength, bool throwException, ArrayStorage*); - void setLengthWritable(ExecState*, bool writable); - - template<IndexingType indexingType> - void compactForSorting(unsigned& numDefined, unsigned& newRelevantLength); + // This form of shift hints that we're just doing care and feeding on an array that + // is probably typically used for ordinary accesses. With this assumption in hand, + // we try to preserve whatever indexing type it has already. + ShiftCountForSplice }; - inline Butterfly* createContiguousArrayButterfly(JSGlobalData& globalData, unsigned length) + bool shiftCountForShift(ExecState* exec, unsigned startIndex, unsigned count) { - IndexingHeader header; - header.setVectorLength(std::max(length, BASE_VECTOR_LEN)); - header.setPublicLength(length); - Butterfly* result = Butterfly::create( - globalData, 0, 0, true, header, header.vectorLength() * sizeof(EncodedJSValue)); - return result; + return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData())); } - - inline Butterfly* createArrayButterfly(JSGlobalData& globalData, unsigned initialLength) + bool shiftCountForSplice(ExecState* exec, unsigned startIndex, unsigned count) { - Butterfly* butterfly = Butterfly::create( - globalData, 0, 0, true, baseIndexingHeaderForArray(initialLength), ArrayStorage::sizeFor(BASE_VECTOR_LEN)); - ArrayStorage* storage = butterfly->arrayStorage(); - storage->m_indexBias = 0; - storage->m_sparseMap.clear(); - storage->m_numValuesInVector = 0; - return butterfly; + return shiftCountWithAnyIndexingType(exec, startIndex, count); } - - Butterfly* createArrayButterflyInDictionaryIndexingMode(JSGlobalData&, unsigned initialLength); - - inline JSArray* JSArray::create(JSGlobalData& globalData, Structure* structure, unsigned initialLength) + template<ShiftCountMode shiftCountMode> + bool shiftCount(ExecState* exec, unsigned startIndex, unsigned count) { - Butterfly* butterfly; - if (LIKELY(structure->indexingType() == ArrayWithContiguous)) { - butterfly = createContiguousArrayButterfly(globalData, initialLength); - ASSERT(initialLength < MIN_SPARSE_ARRAY_INDEX); - } else { - ASSERT( - structure->indexingType() == ArrayWithSlowPutArrayStorage - || (initialLength && structure->indexingType() == ArrayWithArrayStorage)); - butterfly = createArrayButterfly(globalData, initialLength); + switch (shiftCountMode) { + case ShiftCountForShift: + return shiftCountForShift(exec, startIndex, count); + case ShiftCountForSplice: + return shiftCountForSplice(exec, startIndex, count); + default: + CRASH(); + return false; } - JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure, butterfly); - array->finishCreation(globalData); - return array; } - - inline JSArray* JSArray::tryCreateUninitialized(JSGlobalData& globalData, Structure* structure, unsigned initialLength) - { - unsigned vectorLength = std::max(BASE_VECTOR_LEN, initialLength); - if (vectorLength > MAX_STORAGE_VECTOR_LENGTH) - return 0; - Butterfly* butterfly; - if (LIKELY(structure->indexingType() == ArrayWithContiguous)) { - - void* temp; - if (!globalData.heap.tryAllocateStorage(Butterfly::totalSize(0, 0, true, vectorLength * sizeof(EncodedJSValue)), &temp)) - return 0; - butterfly = Butterfly::fromBase(temp, 0, 0); - butterfly->setVectorLength(vectorLength); - butterfly->setPublicLength(initialLength); - } else { - void* temp; - if (!globalData.heap.tryAllocateStorage(Butterfly::totalSize(0, 0, true, ArrayStorage::sizeFor(vectorLength)), &temp)) - return 0; - butterfly = Butterfly::fromBase(temp, 0, 0); - *butterfly->indexingHeader() = indexingHeaderForArray(initialLength, vectorLength); - ArrayStorage* storage = butterfly->arrayStorage(); - storage->m_indexBias = 0; - storage->m_sparseMap.clear(); - storage->m_numValuesInVector = initialLength; + bool unshiftCountForShift(ExecState* exec, unsigned startIndex, unsigned count) + { + return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData())); + } + bool unshiftCountForSplice(ExecState* exec, unsigned startIndex, unsigned count) + { + return unshiftCountWithAnyIndexingType(exec, startIndex, count); + } + template<ShiftCountMode shiftCountMode> + bool unshiftCount(ExecState* exec, unsigned startIndex, unsigned count) + { + switch (shiftCountMode) { + case ShiftCountForShift: + return unshiftCountForShift(exec, startIndex, count); + case ShiftCountForSplice: + return unshiftCountForSplice(exec, startIndex, count); + default: + CRASH(); + return false; } - - JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure, butterfly); - array->finishCreation(globalData); - return array; } - JSArray* asArray(JSValue); + void fillArgList(ExecState*, MarkedArgumentBuffer&); + void copyToArguments(ExecState*, CallFrame*, uint32_t length); - inline JSArray* asArray(JSCell* cell) + static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, IndexingType indexingType) { - ASSERT(cell->inherits(&JSArray::s_info)); - return jsCast<JSArray*>(cell); + return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info, indexingType); } + +protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSObject::StructureFlags; + static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); - inline JSArray* asArray(JSValue value) + static bool deleteProperty(JSCell*, ExecState*, PropertyName); + JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + +private: + bool isLengthWritable() { - return asArray(value.asCell()); + ArrayStorage* storage = arrayStorageOrNull(); + if (!storage) + return true; + SparseArrayValueMap* map = storage->m_sparseMap.get(); + return !map || !map->lengthIsReadOnly(); } + + bool shiftCountWithAnyIndexingType(ExecState*, unsigned startIndex, unsigned count); + bool shiftCountWithArrayStorage(unsigned startIndex, unsigned count, ArrayStorage*); - inline bool isJSArray(JSCell* cell) { return cell->classInfo() == &JSArray::s_info; } - inline bool isJSArray(JSValue v) { return v.isCell() && isJSArray(v.asCell()); } + bool unshiftCountWithAnyIndexingType(ExecState*, unsigned startIndex, unsigned count); + bool unshiftCountWithArrayStorage(ExecState*, unsigned startIndex, unsigned count, ArrayStorage*); + bool unshiftCountSlowCase(JSGlobalData&, bool, unsigned); - inline JSArray* constructArray(ExecState* exec, Structure* arrayStructure, const ArgList& values) - { - JSGlobalData& globalData = exec->globalData(); - unsigned length = values.size(); - JSArray* array = JSArray::tryCreateUninitialized(globalData, arrayStructure, length); - - // FIXME: we should probably throw an out of memory error here, but - // when making this change we should check that all clients of this - // function will correctly handle an exception being thrown from here. - if (!array) - CRASH(); + template<IndexingType indexingType> + void sortNumericVector(ExecState*, JSValue compareFunction, CallType, const CallData&); + + template<IndexingType indexingType> + void sortCompactedVector(ExecState*, WriteBarrier<Unknown>* begin, unsigned relevantLength); + + template<IndexingType indexingType> + void sortVector(ExecState*, JSValue compareFunction, CallType, const CallData&); - for (unsigned i = 0; i < length; ++i) - array->initializeIndex(globalData, i, values.at(i)); - return array; + bool setLengthWithArrayStorage(ExecState*, unsigned newLength, bool throwException, ArrayStorage*); + void setLengthWritable(ExecState*, bool writable); + + template<IndexingType indexingType> + void compactForSorting(unsigned& numDefined, unsigned& newRelevantLength); +}; + +inline Butterfly* createContiguousArrayButterfly(JSGlobalData& globalData, unsigned length) +{ + IndexingHeader header; + header.setVectorLength(std::max(length, BASE_VECTOR_LEN)); + header.setPublicLength(length); + Butterfly* result = Butterfly::create( + globalData, 0, 0, true, header, header.vectorLength() * sizeof(EncodedJSValue)); + return result; +} + +inline Butterfly* createArrayButterfly(JSGlobalData& globalData, unsigned initialLength) +{ + Butterfly* butterfly = Butterfly::create( + globalData, 0, 0, true, baseIndexingHeaderForArray(initialLength), ArrayStorage::sizeFor(BASE_VECTOR_LEN)); + ArrayStorage* storage = butterfly->arrayStorage(); + storage->m_indexBias = 0; + storage->m_sparseMap.clear(); + storage->m_numValuesInVector = 0; + return butterfly; +} + +Butterfly* createArrayButterflyInDictionaryIndexingMode(JSGlobalData&, unsigned initialLength); + +inline JSArray* JSArray::create(JSGlobalData& globalData, Structure* structure, unsigned initialLength) +{ + Butterfly* butterfly; + if (LIKELY(structure->indexingType() == ArrayWithContiguous)) { + butterfly = createContiguousArrayButterfly(globalData, initialLength); + ASSERT(initialLength < MIN_SPARSE_ARRAY_INDEX); + } else { + ASSERT( + structure->indexingType() == ArrayWithSlowPutArrayStorage + || (initialLength && structure->indexingType() == ArrayWithArrayStorage)); + butterfly = createArrayButterfly(globalData, initialLength); } - - inline JSArray* constructArray(ExecState* exec, Structure* arrayStructure, const JSValue* values, unsigned length) - { - JSGlobalData& globalData = exec->globalData(); - JSArray* array = JSArray::tryCreateUninitialized(globalData, arrayStructure, length); - - // FIXME: we should probably throw an out of memory error here, but - // when making this change we should check that all clients of this - // function will correctly handle an exception being thrown from here. - if (!array) - CRASH(); - - for (unsigned i = 0; i < length; ++i) - array->initializeIndex(globalData, i, values[i]); - return array; + JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure, butterfly); + array->finishCreation(globalData); + return array; +} + +inline JSArray* JSArray::tryCreateUninitialized(JSGlobalData& globalData, Structure* structure, unsigned initialLength) +{ + unsigned vectorLength = std::max(BASE_VECTOR_LEN, initialLength); + if (vectorLength > MAX_STORAGE_VECTOR_LENGTH) + return 0; + + Butterfly* butterfly; + if (LIKELY(structure->indexingType() == ArrayWithContiguous)) { + + void* temp; + if (!globalData.heap.tryAllocateStorage(Butterfly::totalSize(0, 0, true, vectorLength * sizeof(EncodedJSValue)), &temp)) + return 0; + butterfly = Butterfly::fromBase(temp, 0, 0); + butterfly->setVectorLength(vectorLength); + butterfly->setPublicLength(initialLength); + } else { + void* temp; + if (!globalData.heap.tryAllocateStorage(Butterfly::totalSize(0, 0, true, ArrayStorage::sizeFor(vectorLength)), &temp)) + return 0; + butterfly = Butterfly::fromBase(temp, 0, 0); + *butterfly->indexingHeader() = indexingHeaderForArray(initialLength, vectorLength); + ArrayStorage* storage = butterfly->arrayStorage(); + storage->m_indexBias = 0; + storage->m_sparseMap.clear(); + storage->m_numValuesInVector = initialLength; } + + JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure, butterfly); + array->finishCreation(globalData); + return array; +} + +JSArray* asArray(JSValue); + +inline JSArray* asArray(JSCell* cell) +{ + ASSERT(cell->inherits(&JSArray::s_info)); + return jsCast<JSArray*>(cell); +} + +inline JSArray* asArray(JSValue value) +{ + return asArray(value.asCell()); +} + +inline bool isJSArray(JSCell* cell) { return cell->classInfo() == &JSArray::s_info; } +inline bool isJSArray(JSValue v) { return v.isCell() && isJSArray(v.asCell()); } + +inline JSArray* constructArray(ExecState* exec, Structure* arrayStructure, const ArgList& values) +{ + JSGlobalData& globalData = exec->globalData(); + unsigned length = values.size(); + JSArray* array = JSArray::tryCreateUninitialized(globalData, arrayStructure, length); + + // FIXME: we should probably throw an out of memory error here, but + // when making this change we should check that all clients of this + // function will correctly handle an exception being thrown from here. + if (!array) + CRASH(); + + for (unsigned i = 0; i < length; ++i) + array->initializeIndex(globalData, i, values.at(i)); + return array; +} + +inline JSArray* constructArray(ExecState* exec, Structure* arrayStructure, const JSValue* values, unsigned length) +{ + JSGlobalData& globalData = exec->globalData(); + JSArray* array = JSArray::tryCreateUninitialized(globalData, arrayStructure, length); + + // FIXME: we should probably throw an out of memory error here, but + // when making this change we should check that all clients of this + // function will correctly handle an exception being thrown from here. + if (!array) + CRASH(); + + for (unsigned i = 0; i < length; ++i) + array->initializeIndex(globalData, i, values[i]); + return array; +} } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h index a39af1283..3b37613d1 100644 --- a/Source/JavaScriptCore/runtime/JSCell.h +++ b/Source/JavaScriptCore/runtime/JSCell.h @@ -38,326 +38,327 @@ namespace JSC { - class CopyVisitor; - class JSDestructibleObject; - class JSGlobalObject; - class LLIntOffsetsExtractor; - class PropertyDescriptor; - class PropertyNameArray; - class Structure; - - enum EnumerationMode { - ExcludeDontEnumProperties, - IncludeDontEnumProperties - }; - - class JSCell { - friend class JSValue; - friend class MarkedBlock; - template<typename T> friend void* allocateCell(Heap&); - template<typename T> friend void* allocateCell(Heap&, size_t); - - public: - static const unsigned StructureFlags = 0; - - static const bool needsDestruction = false; - static const bool hasImmortalStructure = false; - - enum CreatingEarlyCellTag { CreatingEarlyCell }; - JSCell(CreatingEarlyCellTag); - - protected: - JSCell(JSGlobalData&, Structure*); - JS_EXPORT_PRIVATE static void destroy(JSCell*); - - public: - // Querying the type. - bool isString() const; - bool isObject() const; - bool isGetterSetter() const; - bool inherits(const ClassInfo*) const; - bool isAPIValueWrapper() const; - - Structure* structure() const; - void setStructure(JSGlobalData&, Structure*); - void clearStructure() { m_structure.clear(); } - - const char* className(); - - // Extracting the value. - JS_EXPORT_PRIVATE bool getString(ExecState*, String&) const; - JS_EXPORT_PRIVATE String getString(ExecState*) const; // null string if not a string - JS_EXPORT_PRIVATE JSObject* getObject(); // NULL if not an object - const JSObject* getObject() const; // NULL if not an object +class CopyVisitor; +class JSDestructibleObject; +class JSGlobalObject; +class LLIntOffsetsExtractor; +class PropertyDescriptor; +class PropertyNameArray; +class Structure; + +enum EnumerationMode { + ExcludeDontEnumProperties, + IncludeDontEnumProperties +}; + +class JSCell { + friend class JSValue; + friend class MarkedBlock; + template<typename T> friend void* allocateCell(Heap&); + template<typename T> friend void* allocateCell(Heap&, size_t); + +public: + static const unsigned StructureFlags = 0; + + static const bool needsDestruction = false; + static const bool hasImmortalStructure = false; + + enum CreatingEarlyCellTag { CreatingEarlyCell }; + JSCell(CreatingEarlyCellTag); + +protected: + JSCell(JSGlobalData&, Structure*); + JS_EXPORT_PRIVATE static void destroy(JSCell*); + +public: + // Querying the type. + bool isString() const; + bool isObject() const; + bool isGetterSetter() const; + bool isProxy() const; + bool inherits(const ClassInfo*) const; + bool isAPIValueWrapper() const; + + Structure* structure() const; + void setStructure(JSGlobalData&, Structure*); + void clearStructure() { m_structure.clear(); } + + const char* className(); + + // Extracting the value. + JS_EXPORT_PRIVATE bool getString(ExecState*, String&) const; + JS_EXPORT_PRIVATE String getString(ExecState*) const; // null string if not a string + JS_EXPORT_PRIVATE JSObject* getObject(); // NULL if not an object + const JSObject* getObject() const; // NULL if not an object - JS_EXPORT_PRIVATE static CallType getCallData(JSCell*, CallData&); - JS_EXPORT_PRIVATE static ConstructType getConstructData(JSCell*, ConstructData&); - - // Basic conversions. - JS_EXPORT_PRIVATE JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; - bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const; - bool toBoolean(ExecState*) const; - JS_EXPORT_PRIVATE double toNumber(ExecState*) const; - JS_EXPORT_PRIVATE JSObject* toObject(ExecState*, JSGlobalObject*) const; - - static void visitChildren(JSCell*, SlotVisitor&); - JS_EXPORT_PRIVATE static void copyBackingStore(JSCell*, CopyVisitor&); - - // Object operations, with the toObject operation included. - const ClassInfo* classInfo() const; - const MethodTable* methodTable() const; - static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); - static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); + JS_EXPORT_PRIVATE static CallType getCallData(JSCell*, CallData&); + JS_EXPORT_PRIVATE static ConstructType getConstructData(JSCell*, ConstructData&); + + // Basic conversions. + JS_EXPORT_PRIVATE JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; + bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const; + bool toBoolean(ExecState*) const; + JS_EXPORT_PRIVATE double toNumber(ExecState*) const; + JS_EXPORT_PRIVATE JSObject* toObject(ExecState*, JSGlobalObject*) const; + + static void visitChildren(JSCell*, SlotVisitor&); + JS_EXPORT_PRIVATE static void copyBackingStore(JSCell*, CopyVisitor&); + + // Object operations, with the toObject operation included. + const ClassInfo* classInfo() const; + const MethodTable* methodTable() const; + static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); + static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); - static bool deleteProperty(JSCell*, ExecState*, PropertyName); - static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); - - static JSObject* toThisObject(JSCell*, ExecState*); - - void zap() { *reinterpret_cast<uintptr_t**>(this) = 0; } - bool isZapped() const { return !*reinterpret_cast<uintptr_t* const*>(this); } - - // FIXME: Rename getOwnPropertySlot to virtualGetOwnPropertySlot, and - // fastGetOwnPropertySlot to getOwnPropertySlot. Callers should always - // call this function, not its slower virtual counterpart. (For integer - // property names, we want a similar interface with appropriate optimizations.) - bool fastGetOwnPropertySlot(ExecState*, PropertyName, PropertySlot&); - JSValue fastGetOwnProperty(ExecState*, const String&); - - static ptrdiff_t structureOffset() - { - return OBJECT_OFFSETOF(JSCell, m_structure); - } - - void* structureAddress() - { - return &m_structure; - } - -#if ENABLE(GC_VALIDATION) - Structure* unvalidatedStructure() { return m_structure.unvalidatedGet(); } -#endif - - static const TypedArrayType TypedArrayStorageType = TypedArrayNone; - protected: - - void finishCreation(JSGlobalData&); - void finishCreation(JSGlobalData&, Structure*, CreatingEarlyCellTag); - - // Base implementation; for non-object classes implements getPropertySlot. - static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); - static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&); - - // Dummy implementations of override-able static functions for classes to put in their MethodTable - static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType); - static NO_RETURN_DUE_TO_ASSERT void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - static NO_RETURN_DUE_TO_ASSERT void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - static NO_RETURN_DUE_TO_ASSERT void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - static String className(const JSObject*); - JS_EXPORT_PRIVATE static bool customHasInstance(JSObject*, ExecState*, JSValue); - static NO_RETURN_DUE_TO_ASSERT void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes); - static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow); - static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); - - private: - friend class LLIntOffsetsExtractor; - - WriteBarrier<Structure> m_structure; - }; - - inline JSCell::JSCell(CreatingEarlyCellTag) - { - } - - inline void JSCell::finishCreation(JSGlobalData& globalData) - { -#if ENABLE(GC_VALIDATION) - ASSERT(globalData.isInitializingObject()); - globalData.setInitializingObjectClass(0); -#else - UNUSED_PARAM(globalData); -#endif - ASSERT(m_structure); - } - - inline Structure* JSCell::structure() const - { - return m_structure.get(); - } - - inline void JSCell::visitChildren(JSCell* cell, SlotVisitor& visitor) - { - MARK_LOG_PARENT(visitor, cell); - - visitor.append(&cell->m_structure); - } - - // --- JSValue inlines ---------------------------- - - inline bool JSValue::isString() const - { - return isCell() && asCell()->isString(); - } + static bool deleteProperty(JSCell*, ExecState*, PropertyName); + static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); - inline bool JSValue::isPrimitive() const - { - return !isCell() || asCell()->isString(); - } + static JSObject* toThisObject(JSCell*, ExecState*); - inline bool JSValue::isGetterSetter() const - { - return isCell() && asCell()->isGetterSetter(); - } + void zap() { *reinterpret_cast<uintptr_t**>(this) = 0; } + bool isZapped() const { return !*reinterpret_cast<uintptr_t* const*>(this); } - inline bool JSValue::isObject() const - { - return isCell() && asCell()->isObject(); - } + // FIXME: Rename getOwnPropertySlot to virtualGetOwnPropertySlot, and + // fastGetOwnPropertySlot to getOwnPropertySlot. Callers should always + // call this function, not its slower virtual counterpart. (For integer + // property names, we want a similar interface with appropriate optimizations.) + bool fastGetOwnPropertySlot(ExecState*, PropertyName, PropertySlot&); + JSValue fastGetOwnProperty(ExecState*, const String&); - inline bool JSValue::getString(ExecState* exec, String& s) const + static ptrdiff_t structureOffset() { - return isCell() && asCell()->getString(exec, s); + return OBJECT_OFFSETOF(JSCell, m_structure); } - inline String JSValue::getString(ExecState* exec) const + void* structureAddress() { - return isCell() ? asCell()->getString(exec) : String(); + return &m_structure; } + +#if ENABLE(GC_VALIDATION) + Structure* unvalidatedStructure() { return m_structure.unvalidatedGet(); } +#endif + + static const TypedArrayType TypedArrayStorageType = TypedArrayNone; +protected: + + void finishCreation(JSGlobalData&); + void finishCreation(JSGlobalData&, Structure*, CreatingEarlyCellTag); + + // Base implementation; for non-object classes implements getPropertySlot. + static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); + static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&); + + // Dummy implementations of override-able static functions for classes to put in their MethodTable + static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType); + static NO_RETURN_DUE_TO_ASSERT void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + static NO_RETURN_DUE_TO_ASSERT void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + static NO_RETURN_DUE_TO_ASSERT void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + static String className(const JSObject*); + JS_EXPORT_PRIVATE static bool customHasInstance(JSObject*, ExecState*, JSValue); + static NO_RETURN_DUE_TO_ASSERT void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes); + static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow); + static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); + +private: + friend class LLIntOffsetsExtractor; + + WriteBarrier<Structure> m_structure; +}; - template <typename Base> String HandleConverter<Base, Unknown>::getString(ExecState* exec) const - { - return jsValue().getString(exec); - } +inline JSCell::JSCell(CreatingEarlyCellTag) +{ +} - inline JSObject* JSValue::getObject() const - { - return isCell() ? asCell()->getObject() : 0; - } - - ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const - { - if (isInt32()) { - int32_t i = asInt32(); - v = static_cast<uint32_t>(i); - return i >= 0; - } - if (isDouble()) { - double d = asDouble(); - v = static_cast<uint32_t>(d); - return v == d; - } - return false; +inline void JSCell::finishCreation(JSGlobalData& globalData) +{ +#if ENABLE(GC_VALIDATION) + ASSERT(globalData.isInitializingObject()); + globalData.setInitializingObjectClass(0); +#else + UNUSED_PARAM(globalData); +#endif + ASSERT(m_structure); +} + +inline Structure* JSCell::structure() const +{ + return m_structure.get(); +} + +inline void JSCell::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + MARK_LOG_PARENT(visitor, cell); + + visitor.append(&cell->m_structure); +} + +// --- JSValue inlines ---------------------------- + +inline bool JSValue::isString() const +{ + return isCell() && asCell()->isString(); +} + +inline bool JSValue::isPrimitive() const +{ + return !isCell() || asCell()->isString(); +} + +inline bool JSValue::isGetterSetter() const +{ + return isCell() && asCell()->isGetterSetter(); +} + +inline bool JSValue::isObject() const +{ + return isCell() && asCell()->isObject(); +} + +inline bool JSValue::getString(ExecState* exec, String& s) const +{ + return isCell() && asCell()->getString(exec, s); +} + +inline String JSValue::getString(ExecState* exec) const +{ + return isCell() ? asCell()->getString(exec) : String(); +} + +template <typename Base> String HandleConverter<Base, Unknown>::getString(ExecState* exec) const +{ + return jsValue().getString(exec); +} + +inline JSObject* JSValue::getObject() const +{ + return isCell() ? asCell()->getObject() : 0; +} + +ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const +{ + if (isInt32()) { + int32_t i = asInt32(); + v = static_cast<uint32_t>(i); + return i >= 0; } - - inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const - { - return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue(); + if (isDouble()) { + double d = asDouble(); + v = static_cast<uint32_t>(d); + return v == d; } - - inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value) - { - if (isInt32()) { - number = asInt32(); - value = *this; - return true; - } - if (isDouble()) { - number = asDouble(); - value = *this; - return true; - } - if (isCell()) - return asCell()->getPrimitiveNumber(exec, number, value); - if (isTrue()) { - number = 1.0; - value = *this; - return true; - } - if (isFalse() || isNull()) { - number = 0.0; - value = *this; - return true; - } - ASSERT(isUndefined()); - number = std::numeric_limits<double>::quiet_NaN(); + return false; +} + +inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const +{ + return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue(); +} + +inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value) +{ + if (isInt32()) { + number = asInt32(); value = *this; return true; } - - ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const - { - if (isInt32()) - return asInt32(); - if (isDouble()) - return asDouble(); - return toNumberSlowCase(exec); + if (isDouble()) { + number = asDouble(); + value = *this; + return true; } - - inline JSObject* JSValue::toObject(ExecState* exec) const - { - return isCell() ? asCell()->toObject(exec, exec->lexicalGlobalObject()) : toObjectSlowCase(exec, exec->lexicalGlobalObject()); + if (isCell()) + return asCell()->getPrimitiveNumber(exec, number, value); + if (isTrue()) { + number = 1.0; + value = *this; + return true; } - - inline JSObject* JSValue::toObject(ExecState* exec, JSGlobalObject* globalObject) const - { - return isCell() ? asCell()->toObject(exec, globalObject) : toObjectSlowCase(exec, globalObject); + if (isFalse() || isNull()) { + number = 0.0; + value = *this; + return true; } - - template<typename T> - void* allocateCell(Heap& heap, size_t size) - { - ASSERT(size >= sizeof(T)); + ASSERT(isUndefined()); + number = QNaN; + value = *this; + return true; +} + +ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const +{ + if (isInt32()) + return asInt32(); + if (isDouble()) + return asDouble(); + return toNumberSlowCase(exec); +} + +inline JSObject* JSValue::toObject(ExecState* exec) const +{ + return isCell() ? asCell()->toObject(exec, exec->lexicalGlobalObject()) : toObjectSlowCase(exec, exec->lexicalGlobalObject()); +} + +inline JSObject* JSValue::toObject(ExecState* exec, JSGlobalObject* globalObject) const +{ + return isCell() ? asCell()->toObject(exec, globalObject) : toObjectSlowCase(exec, globalObject); +} + +template<typename T> +void* allocateCell(Heap& heap, size_t size) +{ + ASSERT(size >= sizeof(T)); #if ENABLE(GC_VALIDATION) - ASSERT(!heap.globalData()->isInitializingObject()); - heap.globalData()->setInitializingObjectClass(&T::s_info); + ASSERT(!heap.globalData()->isInitializingObject()); + heap.globalData()->setInitializingObjectClass(&T::s_info); #endif - JSCell* result = 0; - if (T::needsDestruction && T::hasImmortalStructure) - result = static_cast<JSCell*>(heap.allocateWithImmortalStructureDestructor(size)); - else if (T::needsDestruction && !T::hasImmortalStructure) - result = static_cast<JSCell*>(heap.allocateWithNormalDestructor(size)); - else - result = static_cast<JSCell*>(heap.allocateWithoutDestructor(size)); - result->clearStructure(); - return result; - } + JSCell* result = 0; + if (T::needsDestruction && T::hasImmortalStructure) + result = static_cast<JSCell*>(heap.allocateWithImmortalStructureDestructor(size)); + else if (T::needsDestruction && !T::hasImmortalStructure) + result = static_cast<JSCell*>(heap.allocateWithNormalDestructor(size)); + else + result = static_cast<JSCell*>(heap.allocateWithoutDestructor(size)); + result->clearStructure(); + return result; +} - template<typename T> - void* allocateCell(Heap& heap) - { - return allocateCell<T>(heap, sizeof(T)); - } +template<typename T> +void* allocateCell(Heap& heap) +{ + return allocateCell<T>(heap, sizeof(T)); +} - inline bool isZapped(const JSCell* cell) - { - return cell->isZapped(); - } - - template<typename To, typename From> - inline To jsCast(From* from) - { - ASSERT(!from || from->JSCell::inherits(&WTF::RemovePointer<To>::Type::s_info)); - return static_cast<To>(from); - } +inline bool isZapped(const JSCell* cell) +{ + return cell->isZapped(); +} + +template<typename To, typename From> +inline To jsCast(From* from) +{ + ASSERT(!from || from->JSCell::inherits(&WTF::RemovePointer<To>::Type::s_info)); + return static_cast<To>(from); +} - template<typename To> - inline To jsCast(JSValue from) - { - ASSERT(from.isCell() && from.asCell()->JSCell::inherits(&WTF::RemovePointer<To>::Type::s_info)); - return static_cast<To>(from.asCell()); - } - - template<typename To, typename From> - inline To jsDynamicCast(From* from) - { - return from->inherits(&WTF::RemovePointer<To>::Type::s_info) ? static_cast<To>(from) : 0; - } - - template<typename To> - inline To jsDynamicCast(JSValue from) - { - return from.isCell() && from.asCell()->inherits(&WTF::RemovePointer<To>::Type::s_info) ? static_cast<To>(from.asCell()) : 0; - } +template<typename To> +inline To jsCast(JSValue from) +{ + ASSERT(from.isCell() && from.asCell()->JSCell::inherits(&WTF::RemovePointer<To>::Type::s_info)); + return static_cast<To>(from.asCell()); +} + +template<typename To, typename From> +inline To jsDynamicCast(From* from) +{ + return from->inherits(&WTF::RemovePointer<To>::Type::s_info) ? static_cast<To>(from) : 0; +} + +template<typename To> +inline To jsDynamicCast(JSValue from) +{ + return from.isCell() && from.asCell()->inherits(&WTF::RemovePointer<To>::Type::s_info) ? static_cast<To>(from.asCell()) : 0; +} } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSDateMath.cpp b/Source/JavaScriptCore/runtime/JSDateMath.cpp index c54147ef2..cd3948fcf 100644 --- a/Source/JavaScriptCore/runtime/JSDateMath.cpp +++ b/Source/JavaScriptCore/runtime/JSDateMath.cpp @@ -247,7 +247,7 @@ double parseDateFromNullTerminatedCharacters(ExecState* exec, const char* dateSt int offset; double ms = WTF::parseDateFromNullTerminatedCharacters(dateString, haveTZ, offset); if (isnan(ms)) - return std::numeric_limits<double>::quiet_NaN(); + return QNaN; // fall back to local timezone if (!haveTZ) { diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.cpp b/Source/JavaScriptCore/runtime/JSGlobalData.cpp index 5fb682bdb..4dca5b0f6 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalData.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalData.cpp @@ -30,6 +30,7 @@ #include "JSGlobalData.h" #include "ArgList.h" +#include "CodeCache.h" #include "CommonIdentifiers.h" #include "DebuggerActivation.h" #include "FunctionConstructor.h" @@ -57,6 +58,7 @@ #include "RegExpObject.h" #include "StrictEvalActivation.h" #include "StrongInlines.h" +#include "UnlinkedCodeBlock.h" #include <wtf/RetainPtr.h> #include <wtf/Threading.h> #include <wtf/WTFThreadData.h> @@ -170,7 +172,7 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, HeapType heapType) , sizeOfLastScratchBuffer(0) #endif , dynamicGlobalObject(0) - , cachedUTCOffset(std::numeric_limits<double>::quiet_NaN()) + , cachedUTCOffset(QNaN) , m_enabledProfiler(0) , m_regExpCache(new RegExpCache(this)) #if ENABLE(REGEXP_TRACING) @@ -196,6 +198,7 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, HeapType heapType) , m_initializingObjectClass(0) #endif , m_inDefineOwnProperty(false) + , m_codeCache(CodeCache::create()) { interpreter = new Interpreter(*this); @@ -221,6 +224,11 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, HeapType heapType) sharedSymbolTableStructure.set(*this, SharedSymbolTable::createStructure(*this, 0, jsNull())); structureChainStructure.set(*this, StructureChain::createStructure(*this, 0, jsNull())); sparseArrayValueMapStructure.set(*this, SparseArrayValueMap::createStructure(*this, 0, jsNull())); + withScopeStructure.set(*this, JSWithScope::createStructure(*this, 0, jsNull())); + unlinkedFunctionExecutableStructure.set(*this, UnlinkedFunctionExecutable::createStructure(*this, 0, jsNull())); + unlinkedProgramCodeBlockStructure.set(*this, UnlinkedProgramCodeBlock::createStructure(*this, 0, jsNull())); + unlinkedEvalCodeBlockStructure.set(*this, UnlinkedEvalCodeBlock::createStructure(*this, 0, jsNull())); + unlinkedFunctionCodeBlockStructure.set(*this, UnlinkedFunctionCodeBlock::createStructure(*this, 0, jsNull())); wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable); @@ -400,10 +408,10 @@ JSGlobalData::ClientData::~ClientData() void JSGlobalData::resetDateCache() { - cachedUTCOffset = std::numeric_limits<double>::quiet_NaN(); + cachedUTCOffset = QNaN; dstOffsetCache.reset(); cachedDateString = String(); - cachedDateStringValue = std::numeric_limits<double>::quiet_NaN(); + cachedDateStringValue = QNaN; dateInstanceCache.reset(); } diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.h b/Source/JavaScriptCore/runtime/JSGlobalData.h index e97c0a015..0ffaccb6a 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalData.h +++ b/Source/JavaScriptCore/runtime/JSGlobalData.h @@ -63,6 +63,7 @@ struct OpaqueJSClassContextData; namespace JSC { class CodeBlock; + class CodeCache; class CommonIdentifiers; class HandleStack; class IdentifierTable; @@ -80,6 +81,10 @@ namespace JSC { #if ENABLE(REGEXP_TRACING) class RegExp; #endif + class UnlinkedCodeBlock; + class UnlinkedEvalCodeBlock; + class UnlinkedFunctionExecutable; + class UnlinkedProgramCodeBlock; struct HashTable; struct Instruction; @@ -223,6 +228,11 @@ namespace JSC { Strong<Structure> sharedSymbolTableStructure; Strong<Structure> structureChainStructure; Strong<Structure> sparseArrayValueMapStructure; + Strong<Structure> withScopeStructure; + Strong<Structure> unlinkedFunctionExecutableStructure; + Strong<Structure> unlinkedProgramCodeBlockStructure; + Strong<Structure> unlinkedEvalCodeBlockStructure; + Strong<Structure> unlinkedFunctionCodeBlockStructure; IdentifierTable* identifierTable; CommonIdentifiers* propertyNames; @@ -436,6 +446,7 @@ namespace JSC { } JSLock& apiLock() { return m_apiLock; } + CodeCache* codeCache() { return m_codeCache.get(); } private: friend class LLIntOffsetsExtractor; @@ -456,6 +467,7 @@ namespace JSC { const ClassInfo* m_initializingObjectClass; #endif bool m_inDefineOwnProperty; + OwnPtr<CodeCache> m_codeCache; TypedArrayDescriptor m_int8ArrayDescriptor; TypedArrayDescriptor m_int16ArrayDescriptor; diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp index 03252fad1..c466a2b04 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -36,6 +36,7 @@ #include "BooleanConstructor.h" #include "BooleanPrototype.h" #include "CodeBlock.h" +#include "CodeCache.h" #include "DateConstructor.h" #include "DatePrototype.h" #include "Debugger.h" @@ -580,4 +581,58 @@ void slowValidateCell(JSGlobalObject* globalObject) ASSERT_GC_OBJECT_INHERITS(globalObject, &JSGlobalObject::s_info); } +UnlinkedProgramCodeBlock* JSGlobalObject::createProgramCodeBlock(CallFrame* callFrame, ProgramExecutable* executable, JSObject** exception) +{ + ParserError error; + JSParserStrictness strictness = executable->isStrictMode() ? JSParseStrict : JSParseNormal; + DebuggerMode debuggerMode = hasDebugger() ? DebuggerOn : DebuggerOff; + ProfilerMode profilerMode = hasProfiler() ? ProfilerOn : ProfilerOff; + UnlinkedProgramCodeBlock* unlinkedCode = globalData().codeCache()->getProgramCodeBlock(globalData(), executable, executable->source(), strictness, debuggerMode, profilerMode, error); + + if (hasDebugger()) + debugger()->sourceParsed(callFrame, executable->source().provider(), error.m_line, error.m_message); + + if (error.m_type != ParserError::ErrorNone) { + *exception = error.toErrorObject(this, executable->source()); + return 0; + } + + return unlinkedCode; +} + +UnlinkedEvalCodeBlock* JSGlobalObject::createEvalCodeBlock(CallFrame* callFrame, EvalExecutable* executable, JSObject** exception) +{ + ParserError error; + JSParserStrictness strictness = executable->isStrictMode() ? JSParseStrict : JSParseNormal; + DebuggerMode debuggerMode = hasDebugger() ? DebuggerOn : DebuggerOff; + ProfilerMode profilerMode = hasProfiler() ? ProfilerOn : ProfilerOff; + UnlinkedEvalCodeBlock* unlinkedCode = globalData().codeCache()->getEvalCodeBlock(globalData(), executable, executable->source(), strictness, debuggerMode, profilerMode, error); + + if (hasDebugger()) + debugger()->sourceParsed(callFrame, executable->source().provider(), error.m_line, error.m_message); + + if (error.m_type != ParserError::ErrorNone) { + *exception = error.toErrorObject(this, executable->source()); + return 0; + } + + return unlinkedCode; +} + +UnlinkedFunctionExecutable* JSGlobalObject::createFunctionExecutableFromGlobalCode(CallFrame* callFrame, const Identifier& name, const SourceCode& code, JSObject** exception) +{ + ParserError error; + UnlinkedFunctionExecutable* executable = globalData().codeCache()->getFunctionExecutableFromGlobalCode(globalData(), name, code, error); + if (hasDebugger()) + debugger()->sourceParsed(callFrame, code.provider(), error.m_line, error.m_message); + + if (error.m_type != ParserError::ErrorNone) { + *exception = error.toErrorObject(this, code); + return 0; + } + + return executable; +} + + } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h index 2994aa64b..3212363ab 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.h +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h @@ -43,6 +43,10 @@ namespace JSC { class Debugger; class ErrorConstructor; class ErrorPrototype; + class EvalCodeBlock; + class EvalExecutable; + class FunctionCodeBlock; + class FunctionExecutable; class FunctionPrototype; class GetterSetter; class GlobalCodeBlock; @@ -50,9 +54,10 @@ namespace JSC { class LLIntOffsetsExtractor; class NativeErrorConstructor; class ProgramCodeBlock; + class ProgramExecutable; class RegExpConstructor; class RegExpPrototype; - + class SourceCode; struct ActivationStackNode; struct HashTable; @@ -185,6 +190,9 @@ namespace JSC { static JS_EXPORTDATA const ClassInfo s_info; + bool hasDebugger() const { return m_debugger; } + bool hasProfiler() const { return globalObjectMethodTable()->supportsProfiling(this); } + protected: JS_EXPORT_PRIVATE explicit JSGlobalObject(JSGlobalData&, Structure*, const GlobalObjectMethodTable* = 0); @@ -271,6 +279,10 @@ namespace JSC { Structure* arrayStructureWithArrayStorage() const { return m_arrayStructureWithArrayStorage.get(); } void* addressOfArrayStructure() { return &m_arrayStructure; } void* addressOfArrayStructureWithArrayStorage() { return &m_arrayStructureWithArrayStorage; } + bool isOriginalArrayStructure(Structure* structure) + { + return structure == m_arrayStructure.get() || structure == m_arrayStructureWithArrayStorage.get(); + } Structure* booleanObjectStructure() const { return m_booleanObjectStructure.get(); } Structure* callbackConstructorStructure() const { return m_callbackConstructorStructure.get(); } Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(); } @@ -362,6 +374,11 @@ namespace JSC { double weakRandomNumber() { return m_weakRandom.get(); } unsigned weakRandomInteger() { return m_weakRandom.getUint32(); } + + UnlinkedProgramCodeBlock* createProgramCodeBlock(CallFrame*, ProgramExecutable*, JSObject** exception); + UnlinkedEvalCodeBlock* createEvalCodeBlock(CallFrame*, EvalExecutable*, JSObject** exception); + UnlinkedFunctionExecutable* createFunctionExecutableFromGlobalCode(CallFrame*, const Identifier&, const SourceCode&, JSObject** exception); + protected: static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | Base::StructureFlags; diff --git a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp index 8b1acb25a..7ac76d350 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp @@ -276,7 +276,7 @@ static double parseInt(const String& s, const CharType* data, int radix) // 8.a If R < 2 or R > 36, then return NaN. if (radix < 2 || radix > 36) - return std::numeric_limits<double>::quiet_NaN(); + return QNaN; // 13. Let mathInt be the mathematical integer value that is represented by Z in radix-R notation, using the letters // A-Z and a-z for digits with values 10 through 35. (However, if R is 10 and Z contains more than 20 significant @@ -299,7 +299,7 @@ static double parseInt(const String& s, const CharType* data, int radix) // 12. If Z is empty, return NaN. if (!sawDigit) - return std::numeric_limits<double>::quiet_NaN(); + return QNaN; // Alternate code path for certain large numbers. if (number >= mantissaOverflowLowerBound) { @@ -397,7 +397,7 @@ static double jsStrDecimalLiteral(const CharType*& data, const CharType* end) } // Not a number. - return std::numeric_limits<double>::quiet_NaN(); + return QNaN; } template <typename CharType> @@ -427,7 +427,7 @@ static double toDouble(const CharType* characters, unsigned size) break; } if (characters != endCharacters) - return std::numeric_limits<double>::quiet_NaN(); + return QNaN; return number; } @@ -443,7 +443,7 @@ double jsToNumber(const String& s) return c - '0'; if (isStrWhiteSpace(c)) return 0; - return std::numeric_limits<double>::quiet_NaN(); + return QNaN; } if (s.is8Bit()) @@ -459,7 +459,7 @@ static double parseFloat(const String& s) UChar c = s[0]; if (isASCIIDigit(c)) return c - '0'; - return std::numeric_limits<double>::quiet_NaN(); + return QNaN; } if (s.is8Bit()) { @@ -474,7 +474,7 @@ static double parseFloat(const String& s) // Empty string. if (data == end) - return std::numeric_limits<double>::quiet_NaN(); + return QNaN; return jsStrDecimalLiteral(data, end); } @@ -490,7 +490,7 @@ static double parseFloat(const String& s) // Empty string. if (data == end) - return std::numeric_limits<double>::quiet_NaN(); + return QNaN; return jsStrDecimalLiteral(data, end); } diff --git a/Source/JavaScriptCore/runtime/JSONObject.cpp b/Source/JavaScriptCore/runtime/JSONObject.cpp index fd939934e..e051ec7d9 100644 --- a/Source/JavaScriptCore/runtime/JSONObject.cpp +++ b/Source/JavaScriptCore/runtime/JSONObject.cpp @@ -294,7 +294,7 @@ static void appendStringToStringBuilder(StringBuilder& builder, const CharType* default: static const char hexDigits[] = "0123456789abcdef"; UChar ch = data[i]; - LChar hex[] = { '\\', 'u', hexDigits[(ch >> 12) & 0xF], hexDigits[(ch >> 8) & 0xF], hexDigits[(ch >> 4) & 0xF], hexDigits[ch & 0xF] }; + LChar hex[] = { '\\', 'u', static_cast<LChar>(hexDigits[(ch >> 12) & 0xF]), static_cast<LChar>(hexDigits[(ch >> 8) & 0xF]), static_cast<LChar>(hexDigits[(ch >> 4) & 0xF]), static_cast<LChar>(hexDigits[ch & 0xF]) }; builder.append(hex, WTF_ARRAY_LENGTH(hex)); break; } diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h index 9204099cb..82455390f 100644 --- a/Source/JavaScriptCore/runtime/JSObject.h +++ b/Source/JavaScriptCore/runtime/JSObject.h @@ -44,810 +44,841 @@ namespace JSC { - inline JSCell* getJSFunction(JSValue value) - { - if (value.isCell() && (value.asCell()->structure()->typeInfo().type() == JSFunctionType)) - return value.asCell(); - return 0; - } +inline JSCell* getJSFunction(JSValue value) +{ + if (value.isCell() && (value.asCell()->structure()->typeInfo().type() == JSFunctionType)) + return value.asCell(); + return 0; +} - JS_EXPORT_PRIVATE JSCell* getCallableObjectSlow(JSCell*); +JS_EXPORT_PRIVATE JSCell* getCallableObjectSlow(JSCell*); - inline JSCell* getCallableObject(JSValue value) - { - if (!value.isCell()) - return 0; - return getCallableObjectSlow(value.asCell()); - } - - class GetterSetter; - class HashEntry; - class InternalFunction; - class LLIntOffsetsExtractor; - class MarkedBlock; - class PropertyDescriptor; - class PropertyNameArray; - class Structure; - struct HashTable; - - JS_EXPORT_PRIVATE JSObject* throwTypeError(ExecState*, const String&); - extern JS_EXPORTDATA const char* StrictModeReadonlyPropertyWriteError; - - // ECMA 262-3 8.6.1 - // Property attributes - enum Attribute { - None = 0, - ReadOnly = 1 << 1, // property can be only read, not written - DontEnum = 1 << 2, // property doesn't appear in (for .. in ..) - DontDelete = 1 << 3, // property can't be deleted - Function = 1 << 4, // property is a function - only used by static hashtables - Accessor = 1 << 5, // property is a getter/setter +inline JSCell* getCallableObject(JSValue value) +{ + if (!value.isCell()) + return 0; + return getCallableObjectSlow(value.asCell()); +} + +class GetterSetter; +class HashEntry; +class InternalFunction; +class LLIntOffsetsExtractor; +class MarkedBlock; +class PropertyDescriptor; +class PropertyNameArray; +class Structure; +struct HashTable; + +JS_EXPORT_PRIVATE JSObject* throwTypeError(ExecState*, const String&); +extern JS_EXPORTDATA const char* StrictModeReadonlyPropertyWriteError; + +// ECMA 262-3 8.6.1 +// Property attributes +enum Attribute { + None = 0, + ReadOnly = 1 << 1, // property can be only read, not written + DontEnum = 1 << 2, // property doesn't appear in (for .. in ..) + DontDelete = 1 << 3, // property can't be deleted + Function = 1 << 4, // property is a function - only used by static hashtables + Accessor = 1 << 5, // property is a getter/setter +}; + +COMPILE_ASSERT(None < FirstInternalAttribute, None_is_below_FirstInternalAttribute); +COMPILE_ASSERT(ReadOnly < FirstInternalAttribute, ReadOnly_is_below_FirstInternalAttribute); +COMPILE_ASSERT(DontEnum < FirstInternalAttribute, DontEnum_is_below_FirstInternalAttribute); +COMPILE_ASSERT(DontDelete < FirstInternalAttribute, DontDelete_is_below_FirstInternalAttribute); +COMPILE_ASSERT(Function < FirstInternalAttribute, Function_is_below_FirstInternalAttribute); +COMPILE_ASSERT(Accessor < FirstInternalAttribute, Accessor_is_below_FirstInternalAttribute); + +class JSFinalObject; + +class JSObject : public JSCell { + friend class BatchedTransitionOptimizer; + friend class JIT; + friend class JSCell; + friend class JSFinalObject; + friend class MarkedBlock; + JS_EXPORT_PRIVATE friend bool setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject*, PropertyName, PropertySlot&); + + enum PutMode { + PutModePut, + PutModeDefineOwnProperty, }; - COMPILE_ASSERT(None < FirstInternalAttribute, None_is_below_FirstInternalAttribute); - COMPILE_ASSERT(ReadOnly < FirstInternalAttribute, ReadOnly_is_below_FirstInternalAttribute); - COMPILE_ASSERT(DontEnum < FirstInternalAttribute, DontEnum_is_below_FirstInternalAttribute); - COMPILE_ASSERT(DontDelete < FirstInternalAttribute, DontDelete_is_below_FirstInternalAttribute); - COMPILE_ASSERT(Function < FirstInternalAttribute, Function_is_below_FirstInternalAttribute); - COMPILE_ASSERT(Accessor < FirstInternalAttribute, Accessor_is_below_FirstInternalAttribute); - - class JSFinalObject; - - class JSObject : public JSCell { - friend class BatchedTransitionOptimizer; - friend class JIT; - friend class JSCell; - friend class JSFinalObject; - friend class MarkedBlock; - JS_EXPORT_PRIVATE friend bool setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject*, PropertyName, PropertySlot&); - - enum PutMode { - PutModePut, - PutModeDefineOwnProperty, - }; - - public: - typedef JSCell Base; +public: + typedef JSCell Base; - static size_t allocationSize(size_t inlineCapacity) - { - return sizeof(JSObject) + inlineCapacity * sizeof(WriteBarrierBase<Unknown>); - } + static size_t allocationSize(size_t inlineCapacity) + { + return sizeof(JSObject) + inlineCapacity * sizeof(WriteBarrierBase<Unknown>); + } - JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); - JS_EXPORT_PRIVATE static void copyBackingStore(JSCell*, CopyVisitor&); + JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); + JS_EXPORT_PRIVATE static void copyBackingStore(JSCell*, CopyVisitor&); - JS_EXPORT_PRIVATE static String className(const JSObject*); + JS_EXPORT_PRIVATE static String className(const JSObject*); - JSValue prototype() const; - void setPrototype(JSGlobalData&, JSValue prototype); - bool setPrototypeWithCycleCheck(JSGlobalData&, JSValue prototype); + JSValue prototype() const; + void setPrototype(JSGlobalData&, JSValue prototype); + bool setPrototypeWithCycleCheck(JSGlobalData&, JSValue prototype); - Structure* inheritorID(JSGlobalData&); - void notifyUsedAsPrototype(JSGlobalData&); + Structure* inheritorID(JSGlobalData&); + void notifyUsedAsPrototype(JSGlobalData&); - bool mayBeUsedAsPrototype(JSGlobalData& globalData) - { - return isValidOffset(structure()->get(globalData, globalData.m_inheritorIDKey)); - } + bool mayBeUsedAsPrototype(JSGlobalData& globalData) + { + return isValidOffset(structure()->get(globalData, globalData.m_inheritorIDKey)); + } - bool mayInterceptIndexedAccesses() - { - return structure()->mayInterceptIndexedAccesses(); - } + bool mayInterceptIndexedAccesses() + { + return structure()->mayInterceptIndexedAccesses(); + } - JSValue get(ExecState*, PropertyName) const; - JSValue get(ExecState*, unsigned propertyName) const; - - bool getPropertySlot(ExecState*, PropertyName, PropertySlot&); - bool getPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); - JS_EXPORT_PRIVATE bool getPropertyDescriptor(ExecState*, PropertyName, PropertyDescriptor&); - - static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); - JS_EXPORT_PRIVATE static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&); - JS_EXPORT_PRIVATE static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); - - bool allowsAccessFrom(ExecState*); - - unsigned getArrayLength() const - { - switch (structure()->indexingType()) { - case ALL_BLANK_INDEXING_TYPES: - return 0; - case ALL_CONTIGUOUS_INDEXING_TYPES: - case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return m_butterfly->publicLength(); - default: - ASSERT_NOT_REACHED(); - return 0; - } + JSValue get(ExecState*, PropertyName) const; + JSValue get(ExecState*, unsigned propertyName) const; + + bool getPropertySlot(ExecState*, PropertyName, PropertySlot&); + bool getPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); + JS_EXPORT_PRIVATE bool getPropertyDescriptor(ExecState*, PropertyName, PropertyDescriptor&); + + static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); + JS_EXPORT_PRIVATE static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&); + JS_EXPORT_PRIVATE static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); + + bool allowsAccessFrom(ExecState*); + + unsigned getArrayLength() const + { + switch (structure()->indexingType()) { + case ALL_BLANK_INDEXING_TYPES: + return 0; + case ALL_CONTIGUOUS_INDEXING_TYPES: + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return m_butterfly->publicLength(); + default: + ASSERT_NOT_REACHED(); + return 0; } + } - unsigned getVectorLength() - { - switch (structure()->indexingType()) { - case ALL_BLANK_INDEXING_TYPES: - return 0; - case ALL_CONTIGUOUS_INDEXING_TYPES: - case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return m_butterfly->vectorLength(); - default: - ASSERT_NOT_REACHED(); - return 0; - } + unsigned getVectorLength() + { + switch (structure()->indexingType()) { + case ALL_BLANK_INDEXING_TYPES: + return 0; + case ALL_CONTIGUOUS_INDEXING_TYPES: + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return m_butterfly->vectorLength(); + default: + ASSERT_NOT_REACHED(); + return 0; } + } - JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); - JS_EXPORT_PRIVATE static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); + JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); + JS_EXPORT_PRIVATE static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); - void putByIndexInline(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow) - { - if (canSetIndexQuickly(propertyName)) { - setIndexQuickly(exec->globalData(), propertyName, value); - return; - } - methodTable()->putByIndex(this, exec, propertyName, value, shouldThrow); + void putByIndexInline(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow) + { + if (canSetIndexQuickly(propertyName)) { + setIndexQuickly(exec->globalData(), propertyName, value); + return; } + methodTable()->putByIndex(this, exec, propertyName, value, shouldThrow); + } - // This is similar to the putDirect* methods: - // - the prototype chain is not consulted - // - accessors are not called. - // - it will ignore extensibility and read-only properties if PutDirectIndexLikePutDirect is passed as the mode (the default). - // This method creates a property with attributes writable, enumerable and configurable all set to true. - bool putDirectIndex(ExecState* exec, unsigned propertyName, JSValue value, unsigned attributes, PutDirectIndexMode mode) - { - if (!attributes && canSetIndexQuicklyForPutDirect(propertyName)) { - setIndexQuickly(exec->globalData(), propertyName, value); - return true; - } - return putDirectIndexBeyondVectorLength(exec, propertyName, value, attributes, mode); - } - bool putDirectIndex(ExecState* exec, unsigned propertyName, JSValue value) - { - return putDirectIndex(exec, propertyName, value, 0, PutDirectIndexLikePutDirect); + // This is similar to the putDirect* methods: + // - the prototype chain is not consulted + // - accessors are not called. + // - it will ignore extensibility and read-only properties if PutDirectIndexLikePutDirect is passed as the mode (the default). + // This method creates a property with attributes writable, enumerable and configurable all set to true. + bool putDirectIndex(ExecState* exec, unsigned propertyName, JSValue value, unsigned attributes, PutDirectIndexMode mode) + { + if (!attributes && canSetIndexQuicklyForPutDirect(propertyName)) { + setIndexQuickly(exec->globalData(), propertyName, value); + return true; } + return putDirectIndexBeyondVectorLength(exec, propertyName, value, attributes, mode); + } + bool putDirectIndex(ExecState* exec, unsigned propertyName, JSValue value) + { + return putDirectIndex(exec, propertyName, value, 0, PutDirectIndexLikePutDirect); + } - // A non-throwing version of putDirect and putDirectIndex. - JS_EXPORT_PRIVATE void putDirectMayBeIndex(ExecState*, PropertyName, JSValue); + // A non-throwing version of putDirect and putDirectIndex. + JS_EXPORT_PRIVATE void putDirectMayBeIndex(ExecState*, PropertyName, JSValue); - bool canGetIndexQuickly(unsigned i) - { - switch (structure()->indexingType()) { - case ALL_BLANK_INDEXING_TYPES: - return false; - case ALL_CONTIGUOUS_INDEXING_TYPES: - return i < m_butterfly->vectorLength() && m_butterfly->contiguous()[i]; - case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return i < m_butterfly->arrayStorage()->vectorLength() && m_butterfly->arrayStorage()->m_vector[i]; - default: - ASSERT_NOT_REACHED(); - return false; - } + bool canGetIndexQuickly(unsigned i) + { + switch (structure()->indexingType()) { + case ALL_BLANK_INDEXING_TYPES: + return false; + case ALL_CONTIGUOUS_INDEXING_TYPES: + return i < m_butterfly->vectorLength() && m_butterfly->contiguous()[i]; + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return i < m_butterfly->arrayStorage()->vectorLength() && m_butterfly->arrayStorage()->m_vector[i]; + default: + ASSERT_NOT_REACHED(); + return false; } + } - JSValue getIndexQuickly(unsigned i) - { - switch (structure()->indexingType()) { - case ALL_CONTIGUOUS_INDEXING_TYPES: + JSValue getIndexQuickly(unsigned i) + { + switch (structure()->indexingType()) { + case ALL_CONTIGUOUS_INDEXING_TYPES: + return m_butterfly->contiguous()[i].get(); + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return m_butterfly->arrayStorage()->m_vector[i].get(); + default: + ASSERT_NOT_REACHED(); + return JSValue(); + } + } + + JSValue tryGetIndexQuickly(unsigned i) + { + switch (structure()->indexingType()) { + case ALL_BLANK_INDEXING_TYPES: + break; + case ALL_CONTIGUOUS_INDEXING_TYPES: + if (i < m_butterfly->publicLength()) return m_butterfly->contiguous()[i].get(); - case ALL_ARRAY_STORAGE_INDEXING_TYPES: + break; + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + if (i < m_butterfly->arrayStorage()->vectorLength()) return m_butterfly->arrayStorage()->m_vector[i].get(); - default: - ASSERT_NOT_REACHED(); - return JSValue(); - } + break; + default: + ASSERT_NOT_REACHED(); + break; } + return JSValue(); + } - JSValue tryGetIndexQuickly(unsigned i) - { - switch (structure()->indexingType()) { - case ALL_BLANK_INDEXING_TYPES: - break; - case ALL_CONTIGUOUS_INDEXING_TYPES: - if (i < m_butterfly->publicLength()) - return m_butterfly->contiguous()[i].get(); - break; - case ALL_ARRAY_STORAGE_INDEXING_TYPES: - if (i < m_butterfly->arrayStorage()->vectorLength()) - return m_butterfly->arrayStorage()->m_vector[i].get(); - break; - default: - ASSERT_NOT_REACHED(); - break; - } - return JSValue(); - } + JSValue getDirectIndex(ExecState* exec, unsigned i) + { + if (JSValue result = tryGetIndexQuickly(i)) + return result; + PropertySlot slot(this); + if (methodTable()->getOwnPropertySlotByIndex(this, exec, i, slot)) + return slot.getValue(exec, i); + return JSValue(); + } - JSValue getDirectIndex(ExecState* exec, unsigned i) - { - if (JSValue result = tryGetIndexQuickly(i)) - return result; - PropertySlot slot(this); - if (methodTable()->getOwnPropertySlotByIndex(this, exec, i, slot)) - return slot.getValue(exec, i); - return JSValue(); - } + JSValue getIndex(ExecState* exec, unsigned i) + { + if (JSValue result = tryGetIndexQuickly(i)) + return result; + return get(exec, i); + } - JSValue getIndex(ExecState* exec, unsigned i) - { - if (JSValue result = tryGetIndexQuickly(i)) - return result; - return get(exec, i); + bool canSetIndexQuickly(unsigned i) + { + switch (structure()->indexingType()) { + case ALL_BLANK_INDEXING_TYPES: + return false; + case ALL_CONTIGUOUS_INDEXING_TYPES: + case NonArrayWithArrayStorage: + case ArrayWithArrayStorage: + return i < m_butterfly->vectorLength(); + case NonArrayWithSlowPutArrayStorage: + case ArrayWithSlowPutArrayStorage: + return i < m_butterfly->arrayStorage()->vectorLength() + && !!m_butterfly->arrayStorage()->m_vector[i]; + default: + ASSERT_NOT_REACHED(); + return false; } + } - bool canSetIndexQuickly(unsigned i) - { - switch (structure()->indexingType()) { - case ALL_BLANK_INDEXING_TYPES: - return false; - case ALL_CONTIGUOUS_INDEXING_TYPES: - case NonArrayWithArrayStorage: - case ArrayWithArrayStorage: - return i < m_butterfly->vectorLength(); - case NonArrayWithSlowPutArrayStorage: - case ArrayWithSlowPutArrayStorage: - return i < m_butterfly->arrayStorage()->vectorLength() - && !!m_butterfly->arrayStorage()->m_vector[i]; - default: - ASSERT_NOT_REACHED(); - return false; - } + bool canSetIndexQuicklyForPutDirect(unsigned i) + { + switch (structure()->indexingType()) { + case ALL_BLANK_INDEXING_TYPES: + return false; + case ALL_CONTIGUOUS_INDEXING_TYPES: + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return i < m_butterfly->vectorLength(); + default: + ASSERT_NOT_REACHED(); + return false; } + } - bool canSetIndexQuicklyForPutDirect(unsigned i) - { - switch (structure()->indexingType()) { - case ALL_BLANK_INDEXING_TYPES: - return false; - case ALL_CONTIGUOUS_INDEXING_TYPES: - case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return i < m_butterfly->vectorLength(); - default: - ASSERT_NOT_REACHED(); - return false; - } + void setIndexQuickly(JSGlobalData& globalData, unsigned i, JSValue v) + { + switch (structure()->indexingType()) { + case ALL_CONTIGUOUS_INDEXING_TYPES: { + ASSERT(i < m_butterfly->vectorLength()); + m_butterfly->contiguous()[i].set(globalData, this, v); + if (i >= m_butterfly->publicLength()) + m_butterfly->setPublicLength(i + 1); + break; } - - void setIndexQuickly(JSGlobalData& globalData, unsigned i, JSValue v) - { - switch (structure()->indexingType()) { - case ALL_CONTIGUOUS_INDEXING_TYPES: { - ASSERT(i < m_butterfly->vectorLength()); - m_butterfly->contiguous()[i].set(globalData, this, v); - if (i >= m_butterfly->publicLength()) - m_butterfly->setPublicLength(i + 1); - break; - } - case ALL_ARRAY_STORAGE_INDEXING_TYPES: { - ArrayStorage* storage = m_butterfly->arrayStorage(); - WriteBarrier<Unknown>& x = storage->m_vector[i]; - JSValue old = x.get(); - x.set(globalData, this, v); - if (!old) { - ++storage->m_numValuesInVector; - if (i >= storage->length()) - storage->setLength(i + 1); - } - break; - } - default: - ASSERT_NOT_REACHED(); + case ALL_ARRAY_STORAGE_INDEXING_TYPES: { + ArrayStorage* storage = m_butterfly->arrayStorage(); + WriteBarrier<Unknown>& x = storage->m_vector[i]; + JSValue old = x.get(); + x.set(globalData, this, v); + if (!old) { + ++storage->m_numValuesInVector; + if (i >= storage->length()) + storage->setLength(i + 1); } + break; } - - void initializeIndex(JSGlobalData& globalData, unsigned i, JSValue v) - { - switch (structure()->indexingType()) { - case ALL_CONTIGUOUS_INDEXING_TYPES: { - ASSERT(i < m_butterfly->publicLength()); - ASSERT(i < m_butterfly->vectorLength()); - m_butterfly->contiguous()[i].set(globalData, this, v); - break; - } - case ALL_ARRAY_STORAGE_INDEXING_TYPES: { - ArrayStorage* storage = m_butterfly->arrayStorage(); - ASSERT(i < storage->length()); - ASSERT(i < storage->m_numValuesInVector); - storage->m_vector[i].set(globalData, this, v); - break; - } - default: - ASSERT_NOT_REACHED(); - } + default: + ASSERT_NOT_REACHED(); } + } - bool hasSparseMap() - { - switch (structure()->indexingType()) { - case ALL_BLANK_INDEXING_TYPES: - case ALL_CONTIGUOUS_INDEXING_TYPES: - return false; - case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return m_butterfly->arrayStorage()->m_sparseMap; - default: - ASSERT_NOT_REACHED(); - return false; - } + void initializeIndex(JSGlobalData& globalData, unsigned i, JSValue v) + { + switch (structure()->indexingType()) { + case ALL_CONTIGUOUS_INDEXING_TYPES: { + ASSERT(i < m_butterfly->publicLength()); + ASSERT(i < m_butterfly->vectorLength()); + m_butterfly->contiguous()[i].set(globalData, this, v); + break; + } + case ALL_ARRAY_STORAGE_INDEXING_TYPES: { + ArrayStorage* storage = m_butterfly->arrayStorage(); + ASSERT(i < storage->length()); + ASSERT(i < storage->m_numValuesInVector); + storage->m_vector[i].set(globalData, this, v); + break; } + default: + ASSERT_NOT_REACHED(); + } + } - bool inSparseIndexingMode() - { - switch (structure()->indexingType()) { - case ALL_BLANK_INDEXING_TYPES: - case ALL_CONTIGUOUS_INDEXING_TYPES: - return false; - case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return m_butterfly->arrayStorage()->inSparseMode(); - default: - ASSERT_NOT_REACHED(); - return false; - } + bool hasSparseMap() + { + switch (structure()->indexingType()) { + case ALL_BLANK_INDEXING_TYPES: + case ALL_CONTIGUOUS_INDEXING_TYPES: + return false; + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return m_butterfly->arrayStorage()->m_sparseMap; + default: + ASSERT_NOT_REACHED(); + return false; } + } - void enterDictionaryIndexingMode(JSGlobalData&); - - // putDirect is effectively an unchecked vesion of 'defineOwnProperty': - // - the prototype chain is not consulted - // - accessors are not called. - // - attributes will be respected (after the call the property will exist with the given attributes) - // - the property name is assumed to not be an index. - JS_EXPORT_PRIVATE static void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes); - void putDirect(JSGlobalData&, PropertyName, JSValue, unsigned attributes = 0); - void putDirect(JSGlobalData&, PropertyName, JSValue, PutPropertySlot&); - void putDirectWithoutTransition(JSGlobalData&, PropertyName, JSValue, unsigned attributes = 0); - void putDirectAccessor(ExecState*, PropertyName, JSValue, unsigned attributes); - - bool propertyIsEnumerable(ExecState*, const Identifier& propertyName) const; - - JS_EXPORT_PRIVATE bool hasProperty(ExecState*, PropertyName) const; - JS_EXPORT_PRIVATE bool hasProperty(ExecState*, unsigned propertyName) const; - bool hasOwnProperty(ExecState*, PropertyName) const; - - JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName); - JS_EXPORT_PRIVATE static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); - - JS_EXPORT_PRIVATE static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType); - - bool hasInstance(ExecState*, JSValue); - static bool defaultHasInstance(ExecState*, JSValue, JSValue prototypeProperty); - - JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - - JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const; - bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const; - JS_EXPORT_PRIVATE double toNumber(ExecState*) const; - JS_EXPORT_PRIVATE JSString* toString(ExecState*) const; - - // NOTE: JSObject and its subclasses must be able to gracefully handle ExecState* = 0, - // because this call may come from inside the compiler. - JS_EXPORT_PRIVATE static JSObject* toThisObject(JSCell*, ExecState*); - - bool getPropertySpecificValue(ExecState*, PropertyName, JSCell*& specificFunction) const; - - // This get function only looks at the property map. - JSValue getDirect(JSGlobalData& globalData, PropertyName propertyName) const - { - PropertyOffset offset = structure()->get(globalData, propertyName); - checkOffset(offset, structure()->typeInfo().type()); - return offset != invalidOffset ? getDirectOffset(offset) : JSValue(); + bool inSparseIndexingMode() + { + switch (structure()->indexingType()) { + case ALL_BLANK_INDEXING_TYPES: + case ALL_CONTIGUOUS_INDEXING_TYPES: + return false; + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return m_butterfly->arrayStorage()->inSparseMode(); + default: + ASSERT_NOT_REACHED(); + return false; } + } + + void enterDictionaryIndexingMode(JSGlobalData&); - WriteBarrierBase<Unknown>* getDirectLocation(JSGlobalData& globalData, PropertyName propertyName) - { - PropertyOffset offset = structure()->get(globalData, propertyName); - checkOffset(offset, structure()->typeInfo().type()); - return isValidOffset(offset) ? locationForOffset(offset) : 0; - } + // putDirect is effectively an unchecked vesion of 'defineOwnProperty': + // - the prototype chain is not consulted + // - accessors are not called. + // - attributes will be respected (after the call the property will exist with the given attributes) + // - the property name is assumed to not be an index. + JS_EXPORT_PRIVATE static void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes); + void putDirect(JSGlobalData&, PropertyName, JSValue, unsigned attributes = 0); + void putDirect(JSGlobalData&, PropertyName, JSValue, PutPropertySlot&); + void putDirectWithoutTransition(JSGlobalData&, PropertyName, JSValue, unsigned attributes = 0); + void putDirectAccessor(ExecState*, PropertyName, JSValue, unsigned attributes); - WriteBarrierBase<Unknown>* getDirectLocation(JSGlobalData& globalData, PropertyName propertyName, unsigned& attributes) - { - JSCell* specificFunction; - PropertyOffset offset = structure()->get(globalData, propertyName, attributes, specificFunction); - return isValidOffset(offset) ? locationForOffset(offset) : 0; - } + bool propertyIsEnumerable(ExecState*, const Identifier& propertyName) const; - bool hasInlineStorage() const { return structure()->hasInlineStorage(); } - ConstPropertyStorage inlineStorageUnsafe() const - { - return bitwise_cast<ConstPropertyStorage>(this + 1); - } - PropertyStorage inlineStorageUnsafe() - { - return bitwise_cast<PropertyStorage>(this + 1); - } - ConstPropertyStorage inlineStorage() const - { - ASSERT(hasInlineStorage()); - return inlineStorageUnsafe(); - } - PropertyStorage inlineStorage() - { - ASSERT(hasInlineStorage()); - return inlineStorageUnsafe(); - } + JS_EXPORT_PRIVATE bool hasProperty(ExecState*, PropertyName) const; + JS_EXPORT_PRIVATE bool hasProperty(ExecState*, unsigned propertyName) const; + bool hasOwnProperty(ExecState*, PropertyName) const; + + JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName); + JS_EXPORT_PRIVATE static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); + + JS_EXPORT_PRIVATE static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType); + + bool hasInstance(ExecState*, JSValue); + static bool defaultHasInstance(ExecState*, JSValue, JSValue prototypeProperty); + + JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + + JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const; + bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const; + JS_EXPORT_PRIVATE double toNumber(ExecState*) const; + JS_EXPORT_PRIVATE JSString* toString(ExecState*) const; + + // NOTE: JSObject and its subclasses must be able to gracefully handle ExecState* = 0, + // because this call may come from inside the compiler. + JS_EXPORT_PRIVATE static JSObject* toThisObject(JSCell*, ExecState*); + + bool getPropertySpecificValue(ExecState*, PropertyName, JSCell*& specificFunction) const; + + // This get function only looks at the property map. + JSValue getDirect(JSGlobalData& globalData, PropertyName propertyName) const + { + PropertyOffset offset = structure()->get(globalData, propertyName); + checkOffset(offset, structure()->typeInfo().type()); + return offset != invalidOffset ? getDirectOffset(offset) : JSValue(); + } + + WriteBarrierBase<Unknown>* getDirectLocation(JSGlobalData& globalData, PropertyName propertyName) + { + PropertyOffset offset = structure()->get(globalData, propertyName); + checkOffset(offset, structure()->typeInfo().type()); + return isValidOffset(offset) ? locationForOffset(offset) : 0; + } + + WriteBarrierBase<Unknown>* getDirectLocation(JSGlobalData& globalData, PropertyName propertyName, unsigned& attributes) + { + JSCell* specificFunction; + PropertyOffset offset = structure()->get(globalData, propertyName, attributes, specificFunction); + return isValidOffset(offset) ? locationForOffset(offset) : 0; + } + + bool hasInlineStorage() const { return structure()->hasInlineStorage(); } + ConstPropertyStorage inlineStorageUnsafe() const + { + return bitwise_cast<ConstPropertyStorage>(this + 1); + } + PropertyStorage inlineStorageUnsafe() + { + return bitwise_cast<PropertyStorage>(this + 1); + } + ConstPropertyStorage inlineStorage() const + { + ASSERT(hasInlineStorage()); + return inlineStorageUnsafe(); + } + PropertyStorage inlineStorage() + { + ASSERT(hasInlineStorage()); + return inlineStorageUnsafe(); + } - const Butterfly* butterfly() const { return m_butterfly; } - Butterfly* butterfly() { return m_butterfly; } + const Butterfly* butterfly() const { return m_butterfly; } + Butterfly* butterfly() { return m_butterfly; } - ConstPropertyStorage outOfLineStorage() const { return m_butterfly->propertyStorage(); } - PropertyStorage outOfLineStorage() { return m_butterfly->propertyStorage(); } - - const WriteBarrierBase<Unknown>* locationForOffset(PropertyOffset offset) const - { - if (isInlineOffset(offset)) - return &inlineStorage()[offsetInInlineStorage(offset)]; - return &outOfLineStorage()[offsetInOutOfLineStorage(offset)]; - } + ConstPropertyStorage outOfLineStorage() const { return m_butterfly->propertyStorage(); } + PropertyStorage outOfLineStorage() { return m_butterfly->propertyStorage(); } - WriteBarrierBase<Unknown>* locationForOffset(PropertyOffset offset) - { - if (isInlineOffset(offset)) - return &inlineStorage()[offsetInInlineStorage(offset)]; - return &outOfLineStorage()[offsetInOutOfLineStorage(offset)]; - } + const WriteBarrierBase<Unknown>* locationForOffset(PropertyOffset offset) const + { + if (isInlineOffset(offset)) + return &inlineStorage()[offsetInInlineStorage(offset)]; + return &outOfLineStorage()[offsetInOutOfLineStorage(offset)]; + } - PropertyOffset offsetForLocation(WriteBarrierBase<Unknown>* location) const - { - PropertyOffset result; - size_t offsetInInlineStorage = location - inlineStorageUnsafe(); - if (offsetInInlineStorage < static_cast<size_t>(firstOutOfLineOffset)) - result = offsetInInlineStorage; - else - result = outOfLineStorage() - location + (firstOutOfLineOffset - 1); - validateOffset(result, structure()->typeInfo().type()); - return result; - } + WriteBarrierBase<Unknown>* locationForOffset(PropertyOffset offset) + { + if (isInlineOffset(offset)) + return &inlineStorage()[offsetInInlineStorage(offset)]; + return &outOfLineStorage()[offsetInOutOfLineStorage(offset)]; + } - void transitionTo(JSGlobalData&, Structure*); - - bool removeDirect(JSGlobalData&, PropertyName); // Return true if anything is removed. - bool hasCustomProperties() { return structure()->didTransition(); } - bool hasGetterSetterProperties() { return structure()->hasGetterSetterProperties(); } - - // putOwnDataProperty has 'put' like semantics, however this method: - // - assumes the object contains no own getter/setter properties. - // - provides no special handling for __proto__ - // - does not walk the prototype chain (to check for accessors or non-writable properties). - // This is used by JSActivation. - bool putOwnDataProperty(JSGlobalData&, PropertyName, JSValue, PutPropertySlot&); - - // Fast access to known property offsets. - JSValue getDirectOffset(PropertyOffset offset) const { return locationForOffset(offset)->get(); } - void putDirectOffset(JSGlobalData& globalData, PropertyOffset offset, JSValue value) { locationForOffset(offset)->set(globalData, this, value); } - void putUndefinedAtDirectOffset(PropertyOffset offset) { locationForOffset(offset)->setUndefined(); } - - JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow); - - bool isGlobalObject() const; - bool isVariableObject() const; - bool isNameScopeObject() const; - bool isActivationObject() const; - bool isErrorInstance() const; - bool isProxy() const; - - void seal(JSGlobalData&); - void freeze(JSGlobalData&); - JS_EXPORT_PRIVATE void preventExtensions(JSGlobalData&); - bool isSealed(JSGlobalData& globalData) { return structure()->isSealed(globalData); } - bool isFrozen(JSGlobalData& globalData) { return structure()->isFrozen(globalData); } - bool isExtensible() { return structure()->isExtensible(); } - bool indexingShouldBeSparse() - { - return !isExtensible() - || structure()->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero(); - } + PropertyOffset offsetForLocation(WriteBarrierBase<Unknown>* location) const + { + PropertyOffset result; + size_t offsetInInlineStorage = location - inlineStorageUnsafe(); + if (offsetInInlineStorage < static_cast<size_t>(firstOutOfLineOffset)) + result = offsetInInlineStorage; + else + result = outOfLineStorage() - location + (firstOutOfLineOffset - 1); + validateOffset(result, structure()->typeInfo().type()); + return result; + } + + void transitionTo(JSGlobalData&, Structure*); + + bool removeDirect(JSGlobalData&, PropertyName); // Return true if anything is removed. + bool hasCustomProperties() { return structure()->didTransition(); } + bool hasGetterSetterProperties() { return structure()->hasGetterSetterProperties(); } + + // putOwnDataProperty has 'put' like semantics, however this method: + // - assumes the object contains no own getter/setter properties. + // - provides no special handling for __proto__ + // - does not walk the prototype chain (to check for accessors or non-writable properties). + // This is used by JSActivation. + bool putOwnDataProperty(JSGlobalData&, PropertyName, JSValue, PutPropertySlot&); + + // Fast access to known property offsets. + JSValue getDirectOffset(PropertyOffset offset) const { return locationForOffset(offset)->get(); } + void putDirectOffset(JSGlobalData& globalData, PropertyOffset offset, JSValue value) { locationForOffset(offset)->set(globalData, this, value); } + void putUndefinedAtDirectOffset(PropertyOffset offset) { locationForOffset(offset)->setUndefined(); } + + JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow); + + bool isGlobalObject() const; + bool isVariableObject() const; + bool isNameScopeObject() const; + bool isActivationObject() const; + bool isErrorInstance() const; + + void seal(JSGlobalData&); + void freeze(JSGlobalData&); + JS_EXPORT_PRIVATE void preventExtensions(JSGlobalData&); + bool isSealed(JSGlobalData& globalData) { return structure()->isSealed(globalData); } + bool isFrozen(JSGlobalData& globalData) { return structure()->isFrozen(globalData); } + bool isExtensible() { return structure()->isExtensible(); } + bool indexingShouldBeSparse() + { + return !isExtensible() + || structure()->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero(); + } - bool staticFunctionsReified() { return structure()->staticFunctionsReified(); } - void reifyStaticFunctionsForDelete(ExecState* exec); + bool staticFunctionsReified() { return structure()->staticFunctionsReified(); } + void reifyStaticFunctionsForDelete(ExecState* exec); - JS_EXPORT_PRIVATE Butterfly* growOutOfLineStorage(JSGlobalData&, size_t oldSize, size_t newSize); - void setButterfly(JSGlobalData&, Butterfly*, Structure*); - void setButterflyWithoutChangingStructure(Butterfly*); // You probably don't want to call this. + JS_EXPORT_PRIVATE Butterfly* growOutOfLineStorage(JSGlobalData&, size_t oldSize, size_t newSize); + void setButterfly(JSGlobalData&, Butterfly*, Structure*); + void setButterflyWithoutChangingStructure(Butterfly*); // You probably don't want to call this. - void setStructureAndReallocateStorageIfNecessary(JSGlobalData&, unsigned oldCapacity, Structure*); - void setStructureAndReallocateStorageIfNecessary(JSGlobalData&, Structure*); + void setStructureAndReallocateStorageIfNecessary(JSGlobalData&, unsigned oldCapacity, Structure*); + void setStructureAndReallocateStorageIfNecessary(JSGlobalData&, Structure*); - void flattenDictionaryObject(JSGlobalData& globalData) - { - structure()->flattenDictionaryStructure(globalData, this); - } + void flattenDictionaryObject(JSGlobalData& globalData) + { + structure()->flattenDictionaryStructure(globalData, this); + } - JSGlobalObject* globalObject() const - { - ASSERT(structure()->globalObject()); - ASSERT(!isGlobalObject() || ((JSObject*)structure()->globalObject()) == this); - return structure()->globalObject(); - } + JSGlobalObject* globalObject() const + { + ASSERT(structure()->globalObject()); + ASSERT(!isGlobalObject() || ((JSObject*)structure()->globalObject()) == this); + return structure()->globalObject(); + } - void switchToSlowPutArrayStorage(JSGlobalData&); + void switchToSlowPutArrayStorage(JSGlobalData&); - // The receiver is the prototype in this case. The following: - // - // asObject(foo->structure()->storedPrototype())->attemptToInterceptPutByIndexOnHoleForPrototype(...) - // - // is equivalent to: - // - // foo->attemptToInterceptPutByIndexOnHole(...); - bool attemptToInterceptPutByIndexOnHoleForPrototype(ExecState*, JSValue thisValue, unsigned propertyName, JSValue, bool shouldThrow); + // The receiver is the prototype in this case. The following: + // + // asObject(foo->structure()->storedPrototype())->attemptToInterceptPutByIndexOnHoleForPrototype(...) + // + // is equivalent to: + // + // foo->attemptToInterceptPutByIndexOnHole(...); + bool attemptToInterceptPutByIndexOnHoleForPrototype(ExecState*, JSValue thisValue, unsigned propertyName, JSValue, bool shouldThrow); - // Returns 0 if contiguous storage cannot be created - either because - // indexing should be sparse or because we're having a bad time. - WriteBarrier<Unknown>* ensureContiguous(JSGlobalData& globalData) - { - if (LIKELY(hasContiguous(structure()->indexingType()))) - return m_butterfly->contiguous(); + // Returns 0 if contiguous storage cannot be created - either because + // indexing should be sparse or because we're having a bad time. + WriteBarrier<Unknown>* ensureContiguous(JSGlobalData& globalData) + { + if (LIKELY(hasContiguous(structure()->indexingType()))) + return m_butterfly->contiguous(); - return ensureContiguousSlow(globalData); - } + return ensureContiguousSlow(globalData); + } - // Ensure that the object is in a mode where it has array storage. Use - // this if you're about to perform actions that would have required the - // object to be converted to have array storage, if it didn't have it - // already. - ArrayStorage* ensureArrayStorage(JSGlobalData& globalData) - { - if (LIKELY(hasArrayStorage(structure()->indexingType()))) - return m_butterfly->arrayStorage(); + // Ensure that the object is in a mode where it has array storage. Use + // this if you're about to perform actions that would have required the + // object to be converted to have array storage, if it didn't have it + // already. + ArrayStorage* ensureArrayStorage(JSGlobalData& globalData) + { + if (LIKELY(hasArrayStorage(structure()->indexingType()))) + return m_butterfly->arrayStorage(); - return ensureArrayStorageSlow(globalData); - } + return ensureArrayStorageSlow(globalData); + } - Butterfly* ensureIndexedStorage(JSGlobalData& globalData) - { - if (LIKELY(hasIndexedProperties(structure()->indexingType()))) - return m_butterfly; + Butterfly* ensureIndexedStorage(JSGlobalData& globalData) + { + if (LIKELY(hasIndexedProperties(structure()->indexingType()))) + return m_butterfly; - return ensureIndexedStorageSlow(globalData); - } + return ensureIndexedStorageSlow(globalData); + } - static size_t offsetOfInlineStorage(); + static size_t offsetOfInlineStorage(); - static ptrdiff_t butterflyOffset() - { - return OBJECT_OFFSETOF(JSObject, m_butterfly); - } + static ptrdiff_t butterflyOffset() + { + return OBJECT_OFFSETOF(JSObject, m_butterfly); + } - void* butterflyAddress() - { - return &m_butterfly; - } + void* butterflyAddress() + { + return &m_butterfly; + } - static JS_EXPORTDATA const ClassInfo s_info; - - protected: - void finishCreation(JSGlobalData& globalData) - { - Base::finishCreation(globalData); - ASSERT(inherits(&s_info)); - ASSERT(!structure()->outOfLineCapacity()); - ASSERT(structure()->isEmpty()); - ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype())); - ASSERT(structure()->isObject()); - ASSERT(classInfo()); - } + static JS_EXPORTDATA const ClassInfo s_info; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); - } +protected: + void finishCreation(JSGlobalData& globalData) + { + Base::finishCreation(globalData); + ASSERT(inherits(&s_info)); + ASSERT(!structure()->outOfLineCapacity()); + ASSERT(structure()->isEmpty()); + ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype())); + ASSERT(structure()->isObject()); + ASSERT(classInfo()); + } - // To instantiate objects you likely want JSFinalObject, below. - // To create derived types you likely want JSNonFinalObject, below. - JSObject(JSGlobalData&, Structure*, Butterfly* = 0); + static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + } + + // To instantiate objects you likely want JSFinalObject, below. + // To create derived types you likely want JSNonFinalObject, below. + JSObject(JSGlobalData&, Structure*, Butterfly* = 0); - void resetInheritorID(JSGlobalData&); + void resetInheritorID(JSGlobalData&); - void visitButterfly(SlotVisitor&, Butterfly*, size_t storageSize); - void copyButterfly(CopyVisitor&, Butterfly*, size_t storageSize); - - // Call this if you know that the object is in a mode where it has array - // storage. This will assert otherwise. - ArrayStorage* arrayStorage() - { - ASSERT(hasArrayStorage(structure()->indexingType())); - return m_butterfly->arrayStorage(); - } + void visitButterfly(SlotVisitor&, Butterfly*, size_t storageSize); + void copyButterfly(CopyVisitor&, Butterfly*, size_t storageSize); + + // Call this if you know that the object is in a mode where it has array + // storage. This will assert otherwise. + ArrayStorage* arrayStorage() + { + ASSERT(hasArrayStorage(structure()->indexingType())); + return m_butterfly->arrayStorage(); + } - // Call this if you want to predicate some actions on whether or not the - // object is in a mode where it has array storage. - ArrayStorage* arrayStorageOrNull() - { - switch (structure()->indexingType()) { - case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return m_butterfly->arrayStorage(); + // Call this if you want to predicate some actions on whether or not the + // object is in a mode where it has array storage. + ArrayStorage* arrayStorageOrNull() + { + switch (structure()->indexingType()) { + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return m_butterfly->arrayStorage(); - default: - return 0; - } + default: + return 0; } + } - ArrayStorage* createArrayStorage(JSGlobalData&, unsigned length, unsigned vectorLength); - ArrayStorage* createInitialArrayStorage(JSGlobalData&); - WriteBarrier<Unknown>* createInitialContiguous(JSGlobalData&, unsigned length); - ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength); - ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&, NonPropertyTransition); - ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&); + ArrayStorage* createArrayStorage(JSGlobalData&, unsigned length, unsigned vectorLength); + ArrayStorage* createInitialArrayStorage(JSGlobalData&); + WriteBarrier<Unknown>* createInitialContiguous(JSGlobalData&, unsigned length); + ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength); + ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&, NonPropertyTransition); + ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&); - ArrayStorage* ensureArrayStorageExistsAndEnterDictionaryIndexingMode(JSGlobalData&); + ArrayStorage* ensureArrayStorageExistsAndEnterDictionaryIndexingMode(JSGlobalData&); - bool defineOwnNonIndexProperty(ExecState*, PropertyName, PropertyDescriptor&, bool throwException); + bool defineOwnNonIndexProperty(ExecState*, PropertyName, PropertyDescriptor&, bool throwException); - void putByIndexBeyondVectorLengthContiguousWithoutAttributes(ExecState*, unsigned propertyName, JSValue); - void putByIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, bool shouldThrow, ArrayStorage*); + void putByIndexBeyondVectorLengthContiguousWithoutAttributes(ExecState*, unsigned propertyName, JSValue); + void putByIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, bool shouldThrow, ArrayStorage*); - bool increaseVectorLength(JSGlobalData&, unsigned newLength); - void deallocateSparseIndexMap(); - bool defineOwnIndexedProperty(ExecState*, unsigned, PropertyDescriptor&, bool throwException); - SparseArrayValueMap* allocateSparseIndexMap(JSGlobalData&); + bool increaseVectorLength(JSGlobalData&, unsigned newLength); + void deallocateSparseIndexMap(); + bool defineOwnIndexedProperty(ExecState*, unsigned, PropertyDescriptor&, bool throwException); + SparseArrayValueMap* allocateSparseIndexMap(JSGlobalData&); - void notifyPresenceOfIndexedAccessors(JSGlobalData&); + void notifyPresenceOfIndexedAccessors(JSGlobalData&); - bool attemptToInterceptPutByIndexOnHole(ExecState*, unsigned index, JSValue, bool shouldThrow); + bool attemptToInterceptPutByIndexOnHole(ExecState*, unsigned index, JSValue, bool shouldThrow); - // Call this if you want setIndexQuickly to succeed and you're sure that - // the array is contiguous. - void ensureContiguousLength(JSGlobalData& globalData, unsigned length) - { - ASSERT(length < MAX_ARRAY_INDEX); - ASSERT(hasContiguous(structure()->indexingType())); + // Call this if you want setIndexQuickly to succeed and you're sure that + // the array is contiguous. + void ensureContiguousLength(JSGlobalData& globalData, unsigned length) + { + ASSERT(length < MAX_ARRAY_INDEX); + ASSERT(hasContiguous(structure()->indexingType())); - if (m_butterfly->vectorLength() < length) - ensureContiguousLengthSlow(globalData, length); + if (m_butterfly->vectorLength() < length) + ensureContiguousLengthSlow(globalData, length); - if (m_butterfly->publicLength() < length) - m_butterfly->setPublicLength(length); - } + if (m_butterfly->publicLength() < length) + m_butterfly->setPublicLength(length); + } - unsigned countElementsInContiguous(Butterfly*); + unsigned countElementsInContiguous(Butterfly*); - template<IndexingType indexingType> - WriteBarrier<Unknown>* indexingData() - { - switch (indexingType) { - case ALL_CONTIGUOUS_INDEXING_TYPES: - return m_butterfly->contiguous(); + template<IndexingType indexingType> + WriteBarrier<Unknown>* indexingData() + { + switch (indexingType) { + case ALL_CONTIGUOUS_INDEXING_TYPES: + return m_butterfly->contiguous(); - case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return m_butterfly->arrayStorage()->m_vector; + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return m_butterfly->arrayStorage()->m_vector; - default: - CRASH(); - return 0; - } + default: + CRASH(); + return 0; } + } + + WriteBarrier<Unknown>* currentIndexingData() + { + switch (structure()->indexingType()) { + case ALL_CONTIGUOUS_INDEXING_TYPES: + return m_butterfly->contiguous(); + + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return m_butterfly->arrayStorage()->m_vector; + + default: + CRASH(); + return 0; + } + } - template<IndexingType indexingType> - unsigned relevantLength() - { - switch (indexingType) { - case ALL_CONTIGUOUS_INDEXING_TYPES: - return m_butterfly->publicLength(); + template<IndexingType indexingType> + unsigned relevantLength() + { + switch (indexingType) { + case ALL_CONTIGUOUS_INDEXING_TYPES: + return m_butterfly->publicLength(); - case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return std::min( - m_butterfly->arrayStorage()->length(), - m_butterfly->arrayStorage()->vectorLength()); + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return std::min( + m_butterfly->arrayStorage()->length(), + m_butterfly->arrayStorage()->vectorLength()); - default: - CRASH(); - return 0; - } + default: + CRASH(); + return 0; } + } - private: - friend class LLIntOffsetsExtractor; + unsigned currentRelevantLength() + { + switch (structure()->indexingType()) { + case ALL_CONTIGUOUS_INDEXING_TYPES: + return m_butterfly->publicLength(); + + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return std::min( + m_butterfly->arrayStorage()->length(), + m_butterfly->arrayStorage()->vectorLength()); + + default: + CRASH(); + return 0; + } + } + +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; - void getObject(); - void getString(ExecState* exec); - void isObject(); - void isString(); + // Nobody should ever ask any of these questions on something already known to be a JSObject. + using JSCell::isAPIValueWrapper; + using JSCell::isGetterSetter; + void getObject(); + void getString(ExecState* exec); + void isObject(); + void isString(); - ArrayStorage* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(JSGlobalData&, ArrayStorage*); + ArrayStorage* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(JSGlobalData&, ArrayStorage*); - template<PutMode> - bool putDirectInternal(JSGlobalData&, PropertyName, JSValue, unsigned attr, PutPropertySlot&, JSCell*); + template<PutMode> + bool putDirectInternal(JSGlobalData&, PropertyName, JSValue, unsigned attr, PutPropertySlot&, JSCell*); - bool inlineGetOwnPropertySlot(ExecState*, PropertyName, PropertySlot&); - JS_EXPORT_PRIVATE void fillGetterPropertySlot(PropertySlot&, PropertyOffset); + bool inlineGetOwnPropertySlot(ExecState*, PropertyName, PropertySlot&); + JS_EXPORT_PRIVATE void fillGetterPropertySlot(PropertySlot&, PropertyOffset); - const HashEntry* findPropertyHashEntry(ExecState*, PropertyName) const; - Structure* createInheritorID(JSGlobalData&); + const HashEntry* findPropertyHashEntry(ExecState*, PropertyName) const; + Structure* createInheritorID(JSGlobalData&); - void putIndexedDescriptor(ExecState*, SparseArrayEntry*, PropertyDescriptor&, PropertyDescriptor& old); + void putIndexedDescriptor(ExecState*, SparseArrayEntry*, PropertyDescriptor&, PropertyDescriptor& old); - void putByIndexBeyondVectorLength(ExecState*, unsigned propertyName, JSValue, bool shouldThrow); - bool putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, unsigned attributes, PutDirectIndexMode, ArrayStorage*); - JS_EXPORT_PRIVATE bool putDirectIndexBeyondVectorLength(ExecState*, unsigned propertyName, JSValue, unsigned attributes, PutDirectIndexMode); + void putByIndexBeyondVectorLength(ExecState*, unsigned propertyName, JSValue, bool shouldThrow); + bool putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, unsigned attributes, PutDirectIndexMode, ArrayStorage*); + JS_EXPORT_PRIVATE bool putDirectIndexBeyondVectorLength(ExecState*, unsigned propertyName, JSValue, unsigned attributes, PutDirectIndexMode); - unsigned getNewVectorLength(unsigned currentVectorLength, unsigned currentLength, unsigned desiredLength); - unsigned getNewVectorLength(unsigned desiredLength); + unsigned getNewVectorLength(unsigned currentVectorLength, unsigned currentLength, unsigned desiredLength); + unsigned getNewVectorLength(unsigned desiredLength); - JS_EXPORT_PRIVATE bool getOwnPropertySlotSlow(ExecState*, PropertyName, PropertySlot&); + JS_EXPORT_PRIVATE bool getOwnPropertySlotSlow(ExecState*, PropertyName, PropertySlot&); - void ensureContiguousLengthSlow(JSGlobalData&, unsigned length); + void ensureContiguousLengthSlow(JSGlobalData&, unsigned length); - WriteBarrier<Unknown>* ensureContiguousSlow(JSGlobalData&); - ArrayStorage* ensureArrayStorageSlow(JSGlobalData&); - Butterfly* ensureIndexedStorageSlow(JSGlobalData&); + WriteBarrier<Unknown>* ensureContiguousSlow(JSGlobalData&); + ArrayStorage* ensureArrayStorageSlow(JSGlobalData&); + Butterfly* ensureIndexedStorageSlow(JSGlobalData&); - protected: - Butterfly* m_butterfly; - }; +protected: + Butterfly* m_butterfly; +}; - // JSNonFinalObject is a type of JSObject that has some internal storage, - // but also preserves some space in the collector cell for additional - // data members in derived types. - class JSNonFinalObject : public JSObject { - friend class JSObject; +// JSNonFinalObject is a type of JSObject that has some internal storage, +// but also preserves some space in the collector cell for additional +// data members in derived types. +class JSNonFinalObject : public JSObject { + friend class JSObject; - public: - typedef JSObject Base; +public: + typedef JSObject Base; - static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); - } + static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); + } - protected: - explicit JSNonFinalObject(JSGlobalData& globalData, Structure* structure, Butterfly* butterfly = 0) - : JSObject(globalData, structure, butterfly) - { - } +protected: + explicit JSNonFinalObject(JSGlobalData& globalData, Structure* structure, Butterfly* butterfly = 0) + : JSObject(globalData, structure, butterfly) + { + } - void finishCreation(JSGlobalData& globalData) - { - Base::finishCreation(globalData); - ASSERT(!this->structure()->totalStorageCapacity()); - ASSERT(classInfo()); - } - }; + void finishCreation(JSGlobalData& globalData) + { + Base::finishCreation(globalData); + ASSERT(!this->structure()->totalStorageCapacity()); + ASSERT(classInfo()); + } +}; - class JSFinalObject; +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 { - friend class JSObject; +// 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 { + friend class JSObject; - public: - typedef JSObject Base; +public: + typedef JSObject Base; - 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, NonArray, INLINE_STORAGE_CAPACITY); - } + 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, NonArray, INLINE_STORAGE_CAPACITY); + } - JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); + JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); - static JS_EXPORTDATA const ClassInfo s_info; + static JS_EXPORTDATA const ClassInfo s_info; - protected: - void visitChildrenCommon(SlotVisitor&); +protected: + void visitChildrenCommon(SlotVisitor&); - void finishCreation(JSGlobalData& globalData) - { - Base::finishCreation(globalData); - ASSERT(structure()->totalStorageCapacity() == structure()->inlineCapacity()); - ASSERT(classInfo()); - } + void finishCreation(JSGlobalData& globalData) + { + Base::finishCreation(globalData); + ASSERT(structure()->totalStorageCapacity() == structure()->inlineCapacity()); + ASSERT(classInfo()); + } - private: - friend class LLIntOffsetsExtractor; +private: + friend class LLIntOffsetsExtractor; - explicit JSFinalObject(JSGlobalData& globalData, Structure* structure) - : JSObject(globalData, structure) - { - } + explicit JSFinalObject(JSGlobalData& globalData, Structure* structure) + : JSObject(globalData, structure) + { + } - static const unsigned StructureFlags = JSObject::StructureFlags; - }; + static const unsigned StructureFlags = JSObject::StructureFlags; +}; inline JSFinalObject* JSFinalObject::create(ExecState* exec, Structure* structure) { @@ -902,11 +933,6 @@ inline bool JSObject::isErrorInstance() const return structure()->typeInfo().type() == ErrorInstanceType; } -inline bool JSObject::isProxy() const -{ - return structure()->typeInfo().type() == ProxyType; -} - inline void JSObject::setButterfly(JSGlobalData& globalData, Butterfly* butterfly, Structure* structure) { ASSERT(structure); diff --git a/Source/JavaScriptCore/runtime/JSScope.cpp b/Source/JavaScriptCore/runtime/JSScope.cpp index 508a90540..8651a76ba 100644 --- a/Source/JavaScriptCore/runtime/JSScope.cpp +++ b/Source/JavaScriptCore/runtime/JSScope.cpp @@ -334,11 +334,14 @@ template <JSScope::LookupMode mode, JSScope::ReturnValues returnValues> JSObject ASSERT(variableObject); ASSERT(variableObject->symbolTable()); SymbolTableEntry entry = variableObject->symbolTable()->get(identifier.impl()); - // Variable was actually inserted by eval + // Defend against the variable being actually inserted by eval. if (entry.isNull()) { ASSERT(!jsDynamicCast<JSNameScope*>(variableObject)); goto fail; } + // If we're getting the 'arguments' then give up on life. + if (identifier == callFrame->propertyNames().arguments) + goto fail; if (putToBaseOperation) { putToBaseOperation->m_kind = entry.isReadOnly() ? PutToBaseOperation::Readonly : PutToBaseOperation::VariablePut; diff --git a/Source/JavaScriptCore/runtime/JSType.h b/Source/JavaScriptCore/runtime/JSType.h index 03f4a7790..10d98d2bd 100644 --- a/Source/JavaScriptCore/runtime/JSType.h +++ b/Source/JavaScriptCore/runtime/JSType.h @@ -41,6 +41,11 @@ enum JSType { ProgramExecutableType, FunctionExecutableType, + UnlinkedFunctionExecutableType, + UnlinkedProgramCodeBlockType, + UnlinkedEvalCodeBlockType, + UnlinkedFunctionCodeBlockType, + // The ObjectType value must come before any JSType that is a subclass of JSObject. ObjectType, FinalObjectType, diff --git a/Source/JavaScriptCore/runtime/JSTypeInfo.h b/Source/JavaScriptCore/runtime/JSTypeInfo.h index d9b3585a0..6f63260fe 100644 --- a/Source/JavaScriptCore/runtime/JSTypeInfo.h +++ b/Source/JavaScriptCore/runtime/JSTypeInfo.h @@ -55,7 +55,7 @@ namespace JSC { , m_flags2(flags >> 8) { ASSERT(flags <= 0x3ff); - ASSERT(type <= 0xff); + ASSERT(static_cast<int>(type) <= 0xff); ASSERT(type >= CompoundType || !(flags & OverridesVisitChildren)); // No object that doesn't ImplementsHasInstance should override it! ASSERT((m_flags & (ImplementsHasInstance | OverridesHasInstance)) != OverridesHasInstance); diff --git a/Source/JavaScriptCore/runtime/JSValue.cpp b/Source/JavaScriptCore/runtime/JSValue.cpp index a5cdf700b..e7f8cad17 100644 --- a/Source/JavaScriptCore/runtime/JSValue.cpp +++ b/Source/JavaScriptCore/runtime/JSValue.cpp @@ -62,7 +62,7 @@ double JSValue::toNumberSlowCase(ExecState* exec) const return asCell()->toNumber(exec); if (isTrue()) return 1.0; - return isUndefined() ? std::numeric_limits<double>::quiet_NaN() : 0; // null and false both convert to 0. + return isUndefined() ? QNaN : 0; // null and false both convert to 0. } JSObject* JSValue::toObjectSlowCase(ExecState* exec, JSGlobalObject* globalObject) const diff --git a/Source/JavaScriptCore/runtime/JSValue.h b/Source/JavaScriptCore/runtime/JSValue.h index 7b5c81aa9..bd9b90466 100644 --- a/Source/JavaScriptCore/runtime/JSValue.h +++ b/Source/JavaScriptCore/runtime/JSValue.h @@ -35,6 +35,10 @@ namespace JSC { +// This is used a lot throughout JavaScriptCore for everything from value boxing to marking +// values as being missing, so it is useful to have it abbreviated. +#define QNaN (std::numeric_limits<double>::quiet_NaN()) + class ExecState; class JSCell; class JSGlobalData; diff --git a/Source/JavaScriptCore/runtime/JSValueInlineMethods.h b/Source/JavaScriptCore/runtime/JSValueInlineMethods.h index 52b747890..224982e9e 100644 --- a/Source/JavaScriptCore/runtime/JSValueInlineMethods.h +++ b/Source/JavaScriptCore/runtime/JSValueInlineMethods.h @@ -62,7 +62,7 @@ namespace JSC { inline JSValue jsNaN() { - return JSValue(std::numeric_limits<double>::quiet_NaN()); + return JSValue(QNaN); } inline JSValue::JSValue(char i) diff --git a/Source/JavaScriptCore/runtime/MathObject.cpp b/Source/JavaScriptCore/runtime/MathObject.cpp index 2f4df375a..7634487ad 100644 --- a/Source/JavaScriptCore/runtime/MathObject.cpp +++ b/Source/JavaScriptCore/runtime/MathObject.cpp @@ -175,7 +175,7 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncMax(ExecState* exec) for (unsigned k = 0; k < argsCount; ++k) { double val = exec->argument(k).toNumber(exec); if (isnan(val)) { - result = std::numeric_limits<double>::quiet_NaN(); + result = QNaN; break; } if (val > result || (val == 0 && result == 0 && !signbit(val))) @@ -191,7 +191,7 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncMin(ExecState* exec) for (unsigned k = 0; k < argsCount; ++k) { double val = exec->argument(k).toNumber(exec); if (isnan(val)) { - result = std::numeric_limits<double>::quiet_NaN(); + result = QNaN; break; } if (val < result || (val == 0 && result == 0 && signbit(val))) diff --git a/Source/JavaScriptCore/runtime/Operations.h b/Source/JavaScriptCore/runtime/Operations.h index 30ba0b27d..01df7e98c 100644 --- a/Source/JavaScriptCore/runtime/Operations.h +++ b/Source/JavaScriptCore/runtime/Operations.h @@ -24,6 +24,7 @@ #include "ExceptionHelpers.h" #include "Interpreter.h" +#include "JSProxy.h" #include "JSString.h" #include "JSValueInlineMethods.h" @@ -297,19 +298,24 @@ namespace JSC { return jsAddSlowCase(callFrame, v1, v2); } +#define InvalidPrototypeChain (std::numeric_limits<size_t>::max()) + inline size_t normalizePrototypeChain(CallFrame* callFrame, JSValue base, JSValue slotBase, const Identifier& propertyName, PropertyOffset& slotOffset) { JSCell* cell = base.asCell(); size_t count = 0; while (slotBase != cell) { + if (cell->isProxy()) + return InvalidPrototypeChain; + JSValue v = cell->structure()->prototypeForLookup(callFrame); // If we didn't find slotBase in base's prototype chain, then base // must be a proxy for another object. if (v.isNull()) - return 0; + return InvalidPrototypeChain; cell = v.asCell(); @@ -332,6 +338,9 @@ namespace JSC { { size_t count = 0; while (1) { + if (base->isProxy()) + return InvalidPrototypeChain; + JSValue v = base->structure()->prototypeForLookup(callFrame); if (v.isNull()) return count; diff --git a/Source/JavaScriptCore/runtime/RegExpObject.cpp b/Source/JavaScriptCore/runtime/RegExpObject.cpp index dfbf533f7..35de40912 100644 --- a/Source/JavaScriptCore/runtime/RegExpObject.cpp +++ b/Source/JavaScriptCore/runtime/RegExpObject.cpp @@ -178,11 +178,34 @@ JSValue regExpObjectMultiline(ExecState*, JSValue slotBase, PropertyName) return jsBoolean(asRegExpObject(slotBase)->regExp()->multiline()); } -JSValue regExpObjectSource(ExecState* exec, JSValue slotBase, PropertyName) +template <typename CharacterType> +static inline void appendLineTerminatorEscape(StringBuilder&, CharacterType); + +template <> +inline void appendLineTerminatorEscape<LChar>(StringBuilder& builder, LChar lineTerminator) +{ + if (lineTerminator == '\n') + builder.append('n'); + else + builder.append('r'); +} + +template <> +inline void appendLineTerminatorEscape<UChar>(StringBuilder& builder, UChar lineTerminator) +{ + if (lineTerminator == '\n') + builder.append('n'); + else if (lineTerminator == '\r') + builder.append('r'); + else if (lineTerminator == 0x2028) + builder.appendLiteral("u2028"); + else + builder.appendLiteral("u2029"); +} + +template <typename CharacterType> +static inline JSValue regExpObjectSourceInternal(ExecState* exec, String pattern, const CharacterType* characters, unsigned length) { - String pattern = asRegExpObject(slotBase)->regExp()->pattern(); - unsigned length = pattern.length(); - const UChar* characters = pattern.characters(); bool previousCharacterWasBackslash = false; bool inBrackets = false; bool shouldEscape = false; @@ -197,7 +220,7 @@ JSValue regExpObjectSource(ExecState* exec, JSValue slotBase, PropertyName) // early return for strings that don't contain a forwards slash and LineTerminator for (unsigned i = 0; i < length; ++i) { - UChar ch = characters[i]; + CharacterType ch = characters[i]; if (!previousCharacterWasBackslash) { if (inBrackets) { if (ch == ']') @@ -212,7 +235,7 @@ JSValue regExpObjectSource(ExecState* exec, JSValue slotBase, PropertyName) } } - if (Lexer<UChar>::isLineTerminator(ch)) { + if (Lexer<CharacterType>::isLineTerminator(ch)) { shouldEscape = true; break; } @@ -230,7 +253,7 @@ JSValue regExpObjectSource(ExecState* exec, JSValue slotBase, PropertyName) inBrackets = false; StringBuilder result; for (unsigned i = 0; i < length; ++i) { - UChar ch = characters[i]; + CharacterType ch = characters[i]; if (!previousCharacterWasBackslash) { if (inBrackets) { if (ch == ']') @@ -244,18 +267,11 @@ JSValue regExpObjectSource(ExecState* exec, JSValue slotBase, PropertyName) } // escape LineTerminator - if (Lexer<UChar>::isLineTerminator(ch)) { + if (Lexer<CharacterType>::isLineTerminator(ch)) { if (!previousCharacterWasBackslash) result.append('\\'); - if (ch == '\n') - result.append('n'); - else if (ch == '\r') - result.append('r'); - else if (ch == 0x2028) - result.appendLiteral("u2028"); - else - result.appendLiteral("u2029"); + appendLineTerminatorEscape<CharacterType>(result, ch); } else result.append(ch); @@ -268,6 +284,14 @@ JSValue regExpObjectSource(ExecState* exec, JSValue slotBase, PropertyName) return jsString(exec, result.toString()); } +JSValue regExpObjectSource(ExecState* exec, JSValue slotBase, PropertyName) +{ + String pattern = asRegExpObject(slotBase)->regExp()->pattern(); + if (pattern.is8Bit()) + return regExpObjectSourceInternal(exec, pattern, pattern.characters8(), pattern.length()); + return regExpObjectSourceInternal(exec, pattern, pattern.characters16(), pattern.length()); +} + void RegExpObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { if (propertyName == exec->propertyNames().lastIndex) { diff --git a/Source/JavaScriptCore/runtime/StringPrototype.cpp b/Source/JavaScriptCore/runtime/StringPrototype.cpp index 4d3ccfda2..5aafe8bb3 100644 --- a/Source/JavaScriptCore/runtime/StringPrototype.cpp +++ b/Source/JavaScriptCore/runtime/StringPrototype.cpp @@ -666,7 +666,7 @@ static inline EncodedJSValue replaceUsingStringSearch(ExecState* exec, JSString* String leftPart(StringImpl::create(stringImpl, 0, matchStart)); size_t matchEnd = matchStart + searchString.impl()->length(); - int ovector[2] = { matchStart, matchEnd}; + int ovector[2] = { static_cast<int>(matchStart), static_cast<int>(matchEnd)}; String middlePart = substituteBackreferences(replaceString, string, ovector, 0); size_t leftLength = stringImpl->length() - matchEnd; diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp index a931def27..e733c7e23 100644 --- a/Source/JavaScriptCore/runtime/Structure.cpp +++ b/Source/JavaScriptCore/runtime/Structure.cpp @@ -543,6 +543,15 @@ Structure* Structure::nonPropertyTransition(JSGlobalData& globalData, Structure* unsigned attributes = toAttributes(transitionKind); IndexingType indexingType = newIndexingType(structure->indexingTypeIncludingHistory(), transitionKind); + JSGlobalObject* globalObject = structure->globalObject(); + if (structure == globalObject->arrayStructure()) { + Structure* transition = globalObject->arrayStructureWithArrayStorage(); + if (transition->indexingTypeIncludingHistory() == indexingType) { + structure->notifyTransitionFromThisStructure(); + return transition; + } + } + if (Structure* existingTransition = structure->m_transitionTable.get(0, attributes)) { ASSERT(existingTransition->m_attributesInPrevious == attributes); ASSERT(existingTransition->indexingTypeIncludingHistory() == indexingType); diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h index 5f1299766..2b25803a6 100644 --- a/Source/JavaScriptCore/runtime/Structure.h +++ b/Source/JavaScriptCore/runtime/Structure.h @@ -521,6 +521,11 @@ namespace JSC { return m_structure->typeInfo().type() == GetterSetterType; } + inline bool JSCell::isProxy() const + { + return structure()->typeInfo().type() == ProxyType; + } + inline bool JSCell::isAPIValueWrapper() const { return m_structure->typeInfo().type() == APIValueWrapperType; diff --git a/Source/JavaScriptCore/runtime/SymbolTable.h b/Source/JavaScriptCore/runtime/SymbolTable.h index debb76499..87d1c8be5 100644 --- a/Source/JavaScriptCore/runtime/SymbolTable.h +++ b/Source/JavaScriptCore/runtime/SymbolTable.h @@ -337,7 +337,7 @@ namespace JSC { struct SymbolTableIndexHashTraits : HashTraits<SymbolTableEntry> { static const bool emptyValueIsZero = true; - static const bool needsDestruction = false; + static const bool needsDestruction = true; }; typedef HashMap<RefPtr<StringImpl>, SymbolTableEntry, IdentifierRepHash, HashTraits<RefPtr<StringImpl> >, SymbolTableIndexHashTraits> SymbolTable; |