diff options
Diffstat (limited to 'JavaScriptCore/runtime')
27 files changed, 513 insertions, 171 deletions
diff --git a/JavaScriptCore/runtime/Arguments.h b/JavaScriptCore/runtime/Arguments.h index 9797e08..9dda24c 100644 --- a/JavaScriptCore/runtime/Arguments.h +++ b/JavaScriptCore/runtime/Arguments.h @@ -220,8 +220,8 @@ namespace JSC { { ASSERT(!d()->registerArray); - size_t numParametersMinusThis = d()->functionExecutable->generatedBytecode().m_numParameters - 1; - size_t numVars = d()->functionExecutable->generatedBytecode().m_numVars; + size_t numParametersMinusThis = d()->functionExecutable->parameterCount(); + size_t numVars = d()->functionExecutable->variableCount(); size_t numLocals = numVars + numParametersMinusThis; if (!numLocals) diff --git a/JavaScriptCore/runtime/ArrayPrototype.cpp b/JavaScriptCore/runtime/ArrayPrototype.cpp index 4c4eb48..99564a8 100644 --- a/JavaScriptCore/runtime/ArrayPrototype.cpp +++ b/JavaScriptCore/runtime/ArrayPrototype.cpp @@ -76,10 +76,10 @@ static inline bool isNumericCompareFunction(ExecState* exec, CallType callType, #if ENABLE(JIT) // If the JIT is enabled then we need to preserve the invariant that every // function with a CodeBlock also has JIT code. - callData.js.functionExecutable->jitCode(exec, callData.js.scopeChain); - CodeBlock& codeBlock = callData.js.functionExecutable->generatedBytecode(); + callData.js.functionExecutable->jitCodeForCall(exec, callData.js.scopeChain); + CodeBlock& codeBlock = callData.js.functionExecutable->generatedBytecodeForCall(); #else - CodeBlock& codeBlock = callData.js.functionExecutable->bytecode(exec, callData.js.scopeChain); + CodeBlock& codeBlock = callData.js.functionExecutable->bytecodeForCall(exec, callData.js.scopeChain); #endif return codeBlock.isNumericCompareFunction(); @@ -271,20 +271,37 @@ JSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec, JSObject*, JSValue thi unsigned k = 0; if (isJSArray(&exec->globalData(), thisObj)) { JSArray* array = asArray(thisObj); - for (; k < length; k++) { - if (!array->canGetIndex(k)) - break; - if (k >= 1) { - if (separator.isNull()) - strBuffer.append(','); - else - strBuffer.append(separator); - } + + if (length) { + if (!array->canGetIndex(k)) + goto skipFirstLoop; JSValue element = array->getIndex(k); if (!element.isUndefinedOrNull()) strBuffer.append(element.toString(exec)); + k++; + } + + if (separator.isNull()) { + for (; k < length; k++) { + if (!array->canGetIndex(k)) + break; + strBuffer.append(','); + JSValue element = array->getIndex(k); + if (!element.isUndefinedOrNull()) + strBuffer.append(element.toString(exec)); + } + } else { + for (; k < length; k++) { + if (!array->canGetIndex(k)) + break; + strBuffer.append(separator); + JSValue element = array->getIndex(k); + if (!element.isUndefinedOrNull()) + strBuffer.append(element.toString(exec)); + } } } + skipFirstLoop: for (; k < length; k++) { if (k >= 1) { if (separator.isNull()) diff --git a/JavaScriptCore/runtime/Collector.cpp b/JavaScriptCore/runtime/Collector.cpp index 05f2bb5..014685f 100644 --- a/JavaScriptCore/runtime/Collector.cpp +++ b/JavaScriptCore/runtime/Collector.cpp @@ -1131,6 +1131,11 @@ Heap::Statistics Heap::statistics() const return statistics; } +size_t Heap::size() const +{ + return m_heap.usedBlocks * BLOCK_SIZE; +} + size_t Heap::globalObjectCount() { size_t count = 0; diff --git a/JavaScriptCore/runtime/Collector.h b/JavaScriptCore/runtime/Collector.h index 3db3d7e..0a40758 100644 --- a/JavaScriptCore/runtime/Collector.h +++ b/JavaScriptCore/runtime/Collector.h @@ -93,6 +93,7 @@ namespace JSC { size_t free; }; Statistics statistics() const; + size_t size() const; void protect(JSValue); // Returns true if the value is no longer protected by any protect pointers diff --git a/JavaScriptCore/runtime/DatePrototype.cpp b/JavaScriptCore/runtime/DatePrototype.cpp index d331409..108ff55 100644 --- a/JavaScriptCore/runtime/DatePrototype.cpp +++ b/JavaScriptCore/runtime/DatePrototype.cpp @@ -2,6 +2,7 @@ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2008, 2009 Torch Mobile, Inc. All rights reserved. + * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -38,6 +39,7 @@ #include <limits.h> #include <locale.h> #include <math.h> +#include <stdlib.h> #include <time.h> #include <wtf/Assertions.h> #include <wtf/DateMath.h> @@ -248,7 +250,27 @@ static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, L strncpy(yearLocation, yearString, yearLen - 1); } - + + // Convert multi-byte result to UNICODE. + // If __STDC_ISO_10646__ is defined, wide character represents + // UTF-16 (or UTF-32) code point. In most modern Unix like system + // (e.g. Linux with glibc 2.2 and above) the macro is defined, + // and wide character represents UTF-32 code point. + // Here we static_cast potential UTF-32 to UTF-16, it should be + // safe because date and (or) time related characters in different languages + // should be in UNICODE BMP. If mbstowcs fails, we just fall + // back on using multi-byte result as-is. +#ifdef __STDC_ISO_10646__ + UChar buffer[bufsize]; + wchar_t tempbuffer[bufsize]; + size_t length = mbstowcs(tempbuffer, timebuffer, bufsize - 1); + if (length != static_cast<size_t>(-1)) { + for (size_t i = 0; i < length; ++i) + buffer[i] = static_cast<UChar>(tempbuffer[i]); + return jsNontrivialString(exec, UString(buffer, length)); + } +#endif + return jsNontrivialString(exec, timebuffer); } diff --git a/JavaScriptCore/runtime/Executable.cpp b/JavaScriptCore/runtime/Executable.cpp index 79900dc..8cb3c56 100644 --- a/JavaScriptCore/runtime/Executable.cpp +++ b/JavaScriptCore/runtime/Executable.cpp @@ -57,7 +57,8 @@ ProgramExecutable::~ProgramExecutable() FunctionExecutable::~FunctionExecutable() { - delete m_codeBlock; + delete m_codeBlockForCall; + delete m_codeBlockForConstruct; } JSObject* EvalExecutable::compile(ExecState* exec, ScopeChainNode* scopeChainNode) @@ -112,7 +113,7 @@ JSObject* ProgramExecutable::compile(ExecState* exec, ScopeChainNode* scopeChain return 0; } -void FunctionExecutable::compile(ExecState*, ScopeChainNode* scopeChainNode) +void FunctionExecutable::compileForCall(ExecState*, ScopeChainNode* scopeChainNode) { JSGlobalData* globalData = scopeChainNode->globalData; RefPtr<FunctionBodyNode> body = globalData->parser->parse<FunctionBodyNode>(globalData, 0, 0, m_source); @@ -124,13 +125,38 @@ void FunctionExecutable::compile(ExecState*, ScopeChainNode* scopeChainNode) ScopeChain scopeChain(scopeChainNode); JSGlobalObject* globalObject = scopeChain.globalObject(); - ASSERT(!m_codeBlock); - m_codeBlock = new FunctionCodeBlock(this, FunctionCode, source().provider(), source().startOffset()); - OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(body.get(), globalObject->debugger(), scopeChain, m_codeBlock->symbolTable(), m_codeBlock)); + ASSERT(!m_codeBlockForCall); + m_codeBlockForCall = new FunctionCodeBlock(this, FunctionCode, source().provider(), source().startOffset(), false); + OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(body.get(), globalObject->debugger(), scopeChain, m_codeBlockForCall->symbolTable(), m_codeBlockForCall)); generator->generate(); - m_numParameters = m_codeBlock->m_numParameters; - ASSERT(m_numParameters); - m_numVariables = m_codeBlock->m_numVars; + m_numParametersForCall = m_codeBlockForCall->m_numParameters; + ASSERT(m_numParametersForCall); + m_numVariables = m_codeBlockForCall->m_numVars; + m_symbolTable = m_codeBlockForCall->sharedSymbolTable(); + + body->destroyData(); +} + +void FunctionExecutable::compileForConstruct(ExecState*, ScopeChainNode* scopeChainNode) +{ + JSGlobalData* globalData = scopeChainNode->globalData; + RefPtr<FunctionBodyNode> body = globalData->parser->parse<FunctionBodyNode>(globalData, 0, 0, m_source); + if (m_forceUsesArguments) + body->setUsesArguments(); + body->finishParsing(m_parameters, m_name); + recordParse(body->features(), body->lineNo(), body->lastLine()); + + ScopeChain scopeChain(scopeChainNode); + JSGlobalObject* globalObject = scopeChain.globalObject(); + + ASSERT(!m_codeBlockForConstruct); + m_codeBlockForConstruct = new FunctionCodeBlock(this, FunctionCode, source().provider(), source().startOffset(), true); + OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(body.get(), globalObject->debugger(), scopeChain, m_codeBlockForConstruct->symbolTable(), m_codeBlockForConstruct)); + generator->generate(); + m_numParametersForConstruct = m_codeBlockForConstruct->m_numParameters; + ASSERT(m_numParametersForConstruct); + m_numVariables = m_codeBlockForConstruct->m_numVars; + m_symbolTable = m_codeBlockForConstruct->sharedSymbolTable(); body->destroyData(); } @@ -140,7 +166,7 @@ void FunctionExecutable::compile(ExecState*, ScopeChainNode* scopeChainNode) void EvalExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChainNode) { CodeBlock* codeBlock = &bytecode(exec, scopeChainNode); - m_jitCode = JIT::compile(scopeChainNode->globalData, codeBlock); + m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, codeBlock); #if !ENABLE(OPCODE_SAMPLING) if (!BytecodeGenerator::dumpsGeneratedCode()) @@ -151,7 +177,7 @@ void EvalExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChain void ProgramExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChainNode) { CodeBlock* codeBlock = &bytecode(exec, scopeChainNode); - m_jitCode = JIT::compile(scopeChainNode->globalData, codeBlock); + m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, codeBlock); #if !ENABLE(OPCODE_SAMPLING) if (!BytecodeGenerator::dumpsGeneratedCode()) @@ -159,10 +185,21 @@ void ProgramExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeCh #endif } -void FunctionExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChainNode) +void FunctionExecutable::generateJITCodeForCall(ExecState* exec, ScopeChainNode* scopeChainNode) { - CodeBlock* codeBlock = &bytecode(exec, scopeChainNode); - m_jitCode = JIT::compile(scopeChainNode->globalData, codeBlock); + CodeBlock* codeBlock = &bytecodeForCall(exec, scopeChainNode); + m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, codeBlock); + +#if !ENABLE(OPCODE_SAMPLING) + if (!BytecodeGenerator::dumpsGeneratedCode()) + codeBlock->discardBytecode(); +#endif +} + +void FunctionExecutable::generateJITCodeForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode) +{ + CodeBlock* codeBlock = &bytecodeForConstruct(exec, scopeChainNode); + m_jitCodeForConstruct = JIT::compile(scopeChainNode->globalData, codeBlock); #if !ENABLE(OPCODE_SAMPLING) if (!BytecodeGenerator::dumpsGeneratedCode()) @@ -174,8 +211,10 @@ void FunctionExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeC void FunctionExecutable::markAggregate(MarkStack& markStack) { - if (m_codeBlock) - m_codeBlock->markAggregate(markStack); + if (m_codeBlockForCall) + m_codeBlockForCall->markAggregate(markStack); + if (m_codeBlockForConstruct) + m_codeBlockForConstruct->markAggregate(markStack); } ExceptionInfo* FunctionExecutable::reparseExceptionInfo(JSGlobalData* globalData, ScopeChainNode* scopeChainNode, CodeBlock* codeBlock) @@ -188,7 +227,7 @@ ExceptionInfo* FunctionExecutable::reparseExceptionInfo(JSGlobalData* globalData ScopeChain scopeChain(scopeChainNode); JSGlobalObject* globalObject = scopeChain.globalObject(); - OwnPtr<CodeBlock> newCodeBlock(new FunctionCodeBlock(this, FunctionCode, source().provider(), source().startOffset())); + OwnPtr<CodeBlock> newCodeBlock(new FunctionCodeBlock(this, FunctionCode, source().provider(), source().startOffset(), codeBlock->m_isConstructor)); globalData->functionCodeBlockBeingReparsed = newCodeBlock.get(); OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(newFunctionBody.get(), globalObject->debugger(), scopeChain, newCodeBlock->symbolTable(), newCodeBlock.get())); @@ -199,7 +238,7 @@ ExceptionInfo* FunctionExecutable::reparseExceptionInfo(JSGlobalData* globalData #if ENABLE(JIT) JITCode newJITCode = JIT::compile(globalData, newCodeBlock.get()); - ASSERT(newJITCode.size() == generatedJITCode().size()); + ASSERT(codeBlock->m_isConstructor ? newJITCode.size() == generatedJITCodeForConstruct().size() : newJITCode.size() == generatedJITCodeForCall().size()); #endif globalData->functionCodeBlockBeingReparsed = 0; @@ -224,7 +263,7 @@ ExceptionInfo* EvalExecutable::reparseExceptionInfo(JSGlobalData* globalData, Sc #if ENABLE(JIT) JITCode newJITCode = JIT::compile(globalData, newCodeBlock.get()); - ASSERT(newJITCode.size() == generatedJITCode().size()); + ASSERT(newJITCode.size() == generatedJITCodeForCall().size()); #endif return newCodeBlock->extractExceptionInfo(); @@ -232,11 +271,15 @@ ExceptionInfo* EvalExecutable::reparseExceptionInfo(JSGlobalData* globalData, Sc void FunctionExecutable::recompile(ExecState*) { - delete m_codeBlock; - m_codeBlock = 0; - m_numParameters = NUM_PARAMETERS_NOT_COMPILED; + delete m_codeBlockForCall; + m_codeBlockForCall = 0; + delete m_codeBlockForConstruct; + m_codeBlockForConstruct = 0; + m_numParametersForCall = NUM_PARAMETERS_NOT_COMPILED; + m_numParametersForConstruct = NUM_PARAMETERS_NOT_COMPILED; #if ENABLE(JIT) - m_jitCode = JITCode(); + m_jitCodeForCall = JITCode(); + m_jitCodeForConstruct = JITCode(); #endif } diff --git a/JavaScriptCore/runtime/Executable.h b/JavaScriptCore/runtime/Executable.h index ac691e4..3e1609e 100644 --- a/JavaScriptCore/runtime/Executable.h +++ b/JavaScriptCore/runtime/Executable.h @@ -36,6 +36,7 @@ namespace JSC { class CodeBlock; class Debugger; class EvalCodeBlock; + class FunctionCodeBlock; class ProgramCodeBlock; class ScopeChainNode; @@ -50,32 +51,40 @@ namespace JSC { public: ExecutableBase(int numParameters) - : m_numParameters(numParameters) + : m_numParametersForCall(numParameters) + , m_numParametersForConstruct(numParameters) { } virtual ~ExecutableBase() {} - bool isHostFunction() const { return m_numParameters == NUM_PARAMETERS_IS_HOST; } + bool isHostFunction() const + { + ASSERT((m_numParametersForCall == NUM_PARAMETERS_IS_HOST) == (m_numParametersForConstruct == NUM_PARAMETERS_IS_HOST)); + return m_numParametersForCall == NUM_PARAMETERS_IS_HOST; + } protected: - int m_numParameters; + int m_numParametersForCall; + int m_numParametersForConstruct; #if ENABLE(JIT) public: - JITCode& generatedJITCode() + JITCode& generatedJITCodeForCall() { - ASSERT(m_jitCode); - return m_jitCode; + ASSERT(m_jitCodeForCall); + return m_jitCodeForCall; } - ExecutablePool* getExecutablePool() + JITCode& generatedJITCodeForConstruct() { - return m_jitCode.getExecutablePool(); + ASSERT(m_jitCodeForConstruct); + return m_jitCodeForConstruct; } protected: - JITCode m_jitCode; + JITCode m_jitCodeForCall; + JITCode m_jitCodeForConstruct; #endif }; @@ -85,12 +94,14 @@ namespace JSC { NativeExecutable(ExecState* exec) : ExecutableBase(NUM_PARAMETERS_IS_HOST) { - m_jitCode = exec->globalData().jitStubs.ctiNativeCallThunk()->m_jitCode; + m_jitCodeForCall = exec->globalData().jitStubs.ctiNativeCallThunk()->m_jitCodeForCall; + m_jitCodeForConstruct = exec->globalData().jitStubs.ctiNativeCallThunk()->m_jitCodeForCall; // FIXME: this thunk should have a construct form } NativeExecutable(JITCode thunk) : ExecutableBase(NUM_PARAMETERS_IS_HOST) { - m_jitCode = thunk; + m_jitCodeForCall = thunk; + m_jitCodeForConstruct = thunk; } ~NativeExecutable(); @@ -192,9 +203,9 @@ namespace JSC { public: JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode) { - if (!m_jitCode) + if (!m_jitCodeForCall) generateJITCode(exec, scopeChainNode); - return m_jitCode; + return m_jitCodeForCall; } private: @@ -238,9 +249,9 @@ namespace JSC { public: JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode) { - if (!m_jitCode) + if (!m_jitCodeForCall) generateJITCode(exec, scopeChainNode); - return m_jitCode; + return m_jitCodeForCall; } private: @@ -268,29 +279,49 @@ namespace JSC { return new (exec) JSFunction(exec, this, scopeChain); } - CodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode) + FunctionCodeBlock& bytecodeForCall(ExecState* exec, ScopeChainNode* scopeChainNode) + { + ASSERT(scopeChainNode); + if (!m_codeBlockForCall) + compileForCall(exec, scopeChainNode); + return *m_codeBlockForCall; + } + + bool isGeneratedForCall() const + { + return m_codeBlockForCall; + } + + FunctionCodeBlock& generatedBytecodeForCall() + { + ASSERT(m_codeBlockForCall); + return *m_codeBlockForCall; + } + + FunctionCodeBlock& bytecodeForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode) { ASSERT(scopeChainNode); - if (!m_codeBlock) - compile(exec, scopeChainNode); - return *m_codeBlock; + if (!m_codeBlockForConstruct) + compileForConstruct(exec, scopeChainNode); + return *m_codeBlockForConstruct; } - bool isGenerated() const + bool isGeneratedForConstruct() const { - return m_codeBlock; + return m_codeBlockForConstruct; } - CodeBlock& generatedBytecode() + FunctionCodeBlock& generatedBytecodeForConstruct() { - ASSERT(m_codeBlock); - return *m_codeBlock; + ASSERT(m_codeBlockForConstruct); + return *m_codeBlockForConstruct; } const Identifier& name() { return m_name; } size_t parameterCount() const { return m_parameters->size(); } - size_t variableCount() const { return m_numVariables; } + unsigned variableCount() const { return m_numVariables; } UString paramString() const; + SharedSymbolTable* symbolTable() const { return m_symbolTable; } void recompile(ExecState*); ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*); @@ -300,11 +331,13 @@ namespace JSC { private: FunctionExecutable(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine) : ScriptExecutable(globalData, source) + , m_numVariables(0) , m_forceUsesArguments(forceUsesArguments) , m_parameters(parameters) - , m_codeBlock(0) + , m_codeBlockForCall(0) + , m_codeBlockForConstruct(0) , m_name(name) - , m_numVariables(0) + , m_symbolTable(0) { m_firstLine = firstLine; m_lastLine = lastLine; @@ -312,35 +345,49 @@ namespace JSC { FunctionExecutable(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine) : ScriptExecutable(exec, source) + , m_numVariables(0) , m_forceUsesArguments(forceUsesArguments) , m_parameters(parameters) - , m_codeBlock(0) + , m_codeBlockForCall(0) + , m_codeBlockForConstruct(0) , m_name(name) - , m_numVariables(0) + , m_symbolTable(0) { m_firstLine = firstLine; m_lastLine = lastLine; } - void compile(ExecState*, ScopeChainNode*); + void compileForCall(ExecState*, ScopeChainNode*); + void compileForConstruct(ExecState*, ScopeChainNode*); + + unsigned m_numVariables : 31; + bool m_forceUsesArguments : 1; - bool m_forceUsesArguments; RefPtr<FunctionParameters> m_parameters; - CodeBlock* m_codeBlock; + FunctionCodeBlock* m_codeBlockForCall; + FunctionCodeBlock* m_codeBlockForConstruct; Identifier m_name; - size_t m_numVariables; + SharedSymbolTable* m_symbolTable; #if ENABLE(JIT) public: - JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode) + JITCode& jitCodeForCall(ExecState* exec, ScopeChainNode* scopeChainNode) { - if (!m_jitCode) - generateJITCode(exec, scopeChainNode); - return m_jitCode; + if (!m_jitCodeForCall) + generateJITCodeForCall(exec, scopeChainNode); + return m_jitCodeForCall; + } + + JITCode& jitCodeForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode) + { + if (!m_jitCodeForConstruct) + generateJITCodeForConstruct(exec, scopeChainNode); + return m_jitCodeForConstruct; } private: - void generateJITCode(ExecState*, ScopeChainNode*); + void generateJITCodeForCall(ExecState*, ScopeChainNode*); + void generateJITCodeForConstruct(ExecState*, ScopeChainNode*); #endif }; diff --git a/JavaScriptCore/runtime/JSActivation.cpp b/JavaScriptCore/runtime/JSActivation.cpp index 85e8bba..f468ff1 100644 --- a/JavaScriptCore/runtime/JSActivation.cpp +++ b/JavaScriptCore/runtime/JSActivation.cpp @@ -134,9 +134,10 @@ JSObject* JSActivation::toThisObject(ExecState* exec) const return exec->globalThisValue(); } -bool JSActivation::isDynamicScope() const +bool JSActivation::isDynamicScope(bool& requiresDynamicChecks) const { - return d()->functionExecutable->usesEval(); + requiresDynamicChecks = d()->functionExecutable->usesEval(); + return false; } JSValue JSActivation::argumentsGetter(ExecState* exec, JSValue slotBase, const Identifier&) diff --git a/JavaScriptCore/runtime/JSActivation.h b/JavaScriptCore/runtime/JSActivation.h index ece8753..a5f8f58 100644 --- a/JavaScriptCore/runtime/JSActivation.h +++ b/JavaScriptCore/runtime/JSActivation.h @@ -47,7 +47,7 @@ namespace JSC { virtual void markChildren(MarkStack&); - virtual bool isDynamicScope() const; + virtual bool isDynamicScope(bool& requiresDynamicChecks) const; virtual bool isActivationObject() const { return true; } @@ -73,12 +73,12 @@ namespace JSC { private: struct JSActivationData : public JSVariableObjectData { JSActivationData(NonNullPassRefPtr<FunctionExecutable> _functionExecutable, Register* registers) - : JSVariableObjectData(_functionExecutable->generatedBytecode().symbolTable(), registers) + : JSVariableObjectData(_functionExecutable->symbolTable(), registers) , functionExecutable(_functionExecutable) { // We have to manually ref and deref the symbol table as JSVariableObjectData // doesn't know about SharedSymbolTable - functionExecutable->generatedBytecode().sharedSymbolTable()->ref(); + functionExecutable->symbolTable()->ref(); } ~JSActivationData() { diff --git a/JavaScriptCore/runtime/JSCell.h b/JavaScriptCore/runtime/JSCell.h index 772708f..ae5aca3 100644 --- a/JavaScriptCore/runtime/JSCell.h +++ b/JavaScriptCore/runtime/JSCell.h @@ -111,12 +111,17 @@ namespace JSC { void* vptr() { return *reinterpret_cast<void**>(this); } void setVPtr(void* vptr) { *reinterpret_cast<void**>(this) = vptr; } + // 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*, const Identifier& propertyName, PropertySlot&); + protected: static const unsigned AnonymousSlotCount = 0; private: // Base implementation; for non-object classes implements getPropertySlot. - bool fastGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); diff --git a/JavaScriptCore/runtime/JSFunction.cpp b/JavaScriptCore/runtime/JSFunction.cpp index 5b73642..c9f295b 100644 --- a/JavaScriptCore/runtime/JSFunction.cpp +++ b/JavaScriptCore/runtime/JSFunction.cpp @@ -106,8 +106,10 @@ JSFunction::~JSFunction() if (!isHostFunction()) { #if ENABLE(JIT_OPTIMIZE_CALL) ASSERT(m_executable); - if (jsExecutable()->isGenerated()) - jsExecutable()->generatedBytecode().unlinkCallers(); + if (jsExecutable()->isGeneratedForCall()) + jsExecutable()->generatedBytecodeForCall().unlinkCallers(); + if (jsExecutable()->isGeneratedForConstruct()) + jsExecutable()->generatedBytecodeForConstruct().unlinkCallers(); #endif scopeChain().~ScopeChain(); // FIXME: Don't we need to do this in the interpreter too? } @@ -136,7 +138,7 @@ CallType JSFunction::getCallData(CallData& callData) JSValue JSFunction::call(ExecState* exec, JSValue thisValue, const ArgList& args) { ASSERT(!isHostFunction()); - return exec->interpreter()->execute(jsExecutable(), exec, this, thisValue.toThisObject(exec), args, scopeChain().node(), exec->exceptionSlot()); + return exec->interpreter()->executeCall(jsExecutable(), exec, this, thisValue.toThisObject(exec), args, scopeChain().node(), exec->exceptionSlot()); } JSValue JSFunction::argumentsGetter(ExecState* exec, JSValue slotBase, const Identifier&) @@ -277,7 +279,7 @@ JSObject* JSFunction::construct(ExecState* exec, const ArgList& args) structure = exec->lexicalGlobalObject()->emptyObjectStructure(); JSObject* thisObj = new (exec) JSObject(structure); - JSValue result = exec->interpreter()->execute(jsExecutable(), exec, this, thisObj, args, scopeChain().node(), exec->exceptionSlot()); + JSValue result = exec->interpreter()->executeConstruct(jsExecutable(), exec, this, thisObj, args, scopeChain().node(), exec->exceptionSlot()); if (exec->hadException() || !result.isObject()) return thisObj; return asObject(result); diff --git a/JavaScriptCore/runtime/JSGlobalData.cpp b/JavaScriptCore/runtime/JSGlobalData.cpp index 12fa2be..652fcb0 100644 --- a/JavaScriptCore/runtime/JSGlobalData.cpp +++ b/JavaScriptCore/runtime/JSGlobalData.cpp @@ -246,7 +246,7 @@ const Vector<Instruction>& JSGlobalData::numericCompareFunction(ExecState* exec) if (!lazyNumericCompareFunction.size() && !initializingLazyNumericCompareFunction) { initializingLazyNumericCompareFunction = true; RefPtr<FunctionExecutable> function = FunctionExecutable::fromGlobalCode(Identifier(exec, "numericCompare"), exec, 0, makeSource(UString("(function (v1, v2) { return v1 - v2; })")), 0, 0); - lazyNumericCompareFunction = function->bytecode(exec, exec->scopeChain()).instructions(); + lazyNumericCompareFunction = function->bytecodeForCall(exec, exec->scopeChain()).instructions(); initializingLazyNumericCompareFunction = false; } diff --git a/JavaScriptCore/runtime/JSGlobalObject.cpp b/JavaScriptCore/runtime/JSGlobalObject.cpp index 7568ffd..7fd491a 100644 --- a/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -426,7 +426,7 @@ ExecState* JSGlobalObject::globalExec() return CallFrame::create(d()->globalCallFrame + RegisterFile::CallFrameHeaderSize); } -bool JSGlobalObject::isDynamicScope() const +bool JSGlobalObject::isDynamicScope(bool&) const { return true; } diff --git a/JavaScriptCore/runtime/JSGlobalObject.h b/JavaScriptCore/runtime/JSGlobalObject.h index df942cf..e38dc79 100644 --- a/JavaScriptCore/runtime/JSGlobalObject.h +++ b/JavaScriptCore/runtime/JSGlobalObject.h @@ -256,7 +256,7 @@ namespace JSC { virtual bool allowsAccessFrom(const JSGlobalObject*) const { return true; } - virtual bool isDynamicScope() const; + virtual bool isDynamicScope(bool& requiresDynamicChecks) const; HashSet<GlobalCodeBlock*>& codeBlocks() { return d()->codeBlocks; } diff --git a/JavaScriptCore/runtime/JSStaticScopeObject.cpp b/JavaScriptCore/runtime/JSStaticScopeObject.cpp index a877ec6..ad10218 100644 --- a/JavaScriptCore/runtime/JSStaticScopeObject.cpp +++ b/JavaScriptCore/runtime/JSStaticScopeObject.cpp @@ -58,7 +58,7 @@ void JSStaticScopeObject::putWithAttributes(ExecState*, const Identifier& proper ASSERT_NOT_REACHED(); } -bool JSStaticScopeObject::isDynamicScope() const +bool JSStaticScopeObject::isDynamicScope(bool&) const { return false; } diff --git a/JavaScriptCore/runtime/JSStaticScopeObject.h b/JavaScriptCore/runtime/JSStaticScopeObject.h index 4d156d4..dcece9d 100644 --- a/JavaScriptCore/runtime/JSStaticScopeObject.h +++ b/JavaScriptCore/runtime/JSStaticScopeObject.h @@ -51,7 +51,7 @@ namespace JSC{ } virtual ~JSStaticScopeObject(); virtual void markChildren(MarkStack&); - bool isDynamicScope() const; + bool isDynamicScope(bool& requiresDynamicChecks) const; virtual JSObject* toThisObject(ExecState*) const; virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&); diff --git a/JavaScriptCore/runtime/JSString.cpp b/JavaScriptCore/runtime/JSString.cpp index fbc7d72..df67133 100644 --- a/JavaScriptCore/runtime/JSString.cpp +++ b/JavaScriptCore/runtime/JSString.cpp @@ -75,8 +75,8 @@ void JSString::resolveRope(ExecState* exec) const // (we will be working backwards over the rope). unsigned fiberCountMinusOne = rope->fiberCount() - 1; for (unsigned i = 0; i < fiberCountMinusOne; ++i) - workQueue.append(rope->fibers(i)); - currentFiber = rope->fibers(fiberCountMinusOne); + workQueue.append(rope->fibers()[i]); + currentFiber = rope->fibers()[fiberCountMinusOne]; } else { UStringImpl* string = static_cast<UStringImpl*>(currentFiber); unsigned length = string->length(); @@ -104,6 +104,57 @@ void JSString::resolveRope(ExecState* exec) const } } +JSValue JSString::replaceCharacter(ExecState* exec, UChar character, const UString& replacement) +{ + if (!isRope()) { + unsigned matchPosition = m_value.find(character); + if (matchPosition == UString::NotFound) + return JSValue(this); + return jsString(exec, m_value.substr(0, matchPosition), replacement, m_value.substr(matchPosition + 1)); + } + + RopeIterator end; + + // Count total fibers and find matching string. + size_t fiberCount = 0; + UStringImpl* matchString = 0; + int matchPosition = -1; + for (RopeIterator it(m_other.m_fibers, m_fiberCount); it != end; ++it) { + ++fiberCount; + if (matchString) + continue; + + UStringImpl* string = *it; + matchPosition = string->find(character); + if (matchPosition == -1) + continue; + matchString = string; + } + + if (!matchString) + return this; + + RopeBuilder builder(replacement.size() ? fiberCount + 2 : fiberCount + 1); + if (UNLIKELY(builder.isOutOfMemory())) + return throwOutOfMemoryError(exec); + + for (RopeIterator it(m_other.m_fibers, m_fiberCount); it != end; ++it) { + UStringImpl* string = *it; + if (string != matchString) { + builder.append(UString(string)); + continue; + } + + builder.append(UString(string).substr(0, matchPosition)); + if (replacement.size()) + builder.append(replacement); + builder.append(UString(string).substr(matchPosition + 1)); + } + + JSGlobalData* globalData = &exec->globalData(); + return JSValue(new (globalData) JSString(globalData, builder.release())); +} + JSString* JSString::getIndexSlowCase(ExecState* exec, unsigned i) { ASSERT(isRope()); diff --git a/JavaScriptCore/runtime/JSString.h b/JavaScriptCore/runtime/JSString.h index 85d3c8e..5001b01 100644 --- a/JavaScriptCore/runtime/JSString.h +++ b/JavaScriptCore/runtime/JSString.h @@ -111,6 +111,79 @@ namespace JSC { RefPtr<RopeImpl> m_rope; }; + class RopeIterator { + public: + RopeIterator() { } + + RopeIterator(RopeImpl::Fiber* fibers, size_t fiberCount) + { + ASSERT(fiberCount); + m_workQueue.append(WorkItem(fibers, fiberCount)); + skipRopes(); + } + + RopeIterator& operator++() + { + WorkItem& item = m_workQueue.last(); + ASSERT(!RopeImpl::isRope(item.fibers[item.i])); + if (++item.i == item.fiberCount) + m_workQueue.removeLast(); + skipRopes(); + return *this; + } + + UStringImpl* operator*() + { + WorkItem& item = m_workQueue.last(); + RopeImpl::Fiber fiber = item.fibers[item.i]; + ASSERT(!RopeImpl::isRope(fiber)); + return static_cast<UStringImpl*>(fiber); + } + + bool operator!=(const RopeIterator& other) const + { + return m_workQueue != other.m_workQueue; + } + + private: + struct WorkItem { + WorkItem(RopeImpl::Fiber* fibers, size_t fiberCount) + : fibers(fibers) + , fiberCount(fiberCount) + , i(0) + { + } + + bool operator!=(const WorkItem& other) const + { + return fibers != other.fibers || fiberCount != other.fiberCount || i != other.i; + } + + RopeImpl::Fiber* fibers; + size_t fiberCount; + size_t i; + }; + + void skipRopes() + { + if (m_workQueue.isEmpty()) + return; + + while (1) { + WorkItem& item = m_workQueue.last(); + RopeImpl::Fiber fiber = item.fibers[item.i]; + if (!RopeImpl::isRope(fiber)) + break; + RopeImpl* rope = static_cast<RopeImpl*>(fiber); + if (++item.i == item.fiberCount) + m_workQueue.removeLast(); + m_workQueue.append(WorkItem(rope->fibers(), rope->fiberCount())); + } + } + + Vector<WorkItem, 16> m_workQueue; + }; + ALWAYS_INLINE JSString(JSGlobalData* globalData, const UString& value) : JSCell(globalData->stringStructure.get()) , m_length(value.size()) @@ -130,7 +203,7 @@ namespace JSC { { ASSERT(!m_value.isNull()); } - JSString(JSGlobalData* globalData, PassRefPtr<UString::Rep> value, HasOtherOwnerType) + JSString(JSGlobalData* globalData, PassRefPtr<UStringImpl> value, HasOtherOwnerType) : JSCell(globalData->stringStructure.get()) , m_length(value->length()) , m_value(value) @@ -200,6 +273,31 @@ namespace JSC { ASSERT(index == s_maxInternalRopeLength); } + // This constructor constructs a new string by concatenating u1 & u2. + JSString(JSGlobalData* globalData, const UString& u1, const UString& u2) + : JSCell(globalData->stringStructure.get()) + , m_length(u1.size() + u2.size()) + , m_fiberCount(2) + { + unsigned index = 0; + appendStringInConstruct(index, u1); + appendStringInConstruct(index, u2); + ASSERT(index <= s_maxInternalRopeLength); + } + + // This constructor constructs a new string by concatenating u1, u2 & u3. + JSString(JSGlobalData* globalData, const UString& u1, const UString& u2, const UString& u3) + : JSCell(globalData->stringStructure.get()) + , m_length(u1.size() + u2.size() + u3.size()) + , m_fiberCount(s_maxInternalRopeLength) + { + unsigned index = 0; + appendStringInConstruct(index, u1); + appendStringInConstruct(index, u2); + appendStringInConstruct(index, u3); + ASSERT(index <= s_maxInternalRopeLength); + } + JSString(JSGlobalData* globalData, const UString& value, JSStringFinalizerCallback finalizer, void* context) : JSCell(globalData->stringStructure.get()) , m_length(value.size()) @@ -246,6 +344,8 @@ namespace JSC { JSString* getIndex(ExecState*, unsigned); JSString* getIndexSlowCase(ExecState*, unsigned); + JSValue replaceCharacter(ExecState*, UChar, const UString& replacement); + static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion), AnonymousSlotCount); } private: @@ -282,7 +382,7 @@ namespace JSC { if (v.isString()) { ASSERT(asCell(v)->isString()); JSString* s = static_cast<JSString*>(asCell(v)); - ASSERT(s->fiberCount() == 1); + ASSERT(s->size() == 1); appendStringInConstruct(index, s); m_length += s->length(); } else { @@ -328,7 +428,7 @@ namespace JSC { bool isRope() const { return m_fiberCount; } UString& string() { ASSERT(!isRope()); return m_value; } - unsigned fiberCount() { return m_fiberCount ? m_fiberCount : 1; } + unsigned size() { return m_fiberCount ? m_fiberCount : 1; } friend JSValue jsString(ExecState* exec, JSString* s1, JSString* s2); friend JSValue jsString(ExecState* exec, const UString& u1, JSString* s2); @@ -375,7 +475,7 @@ namespace JSC { UChar c = s.data()[offset]; if (c <= 0xFF) return globalData->smallStrings.singleCharacterString(globalData, c); - return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, 1)))); + return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UStringImpl::create(s.rep(), offset, 1)))); } inline JSString* jsNontrivialString(JSGlobalData* globalData, const char* s) @@ -433,7 +533,7 @@ namespace JSC { if (c <= 0xFF) return globalData->smallStrings.singleCharacterString(globalData, c); } - return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, length)), JSString::HasOtherOwner)); + return fixupVPtr(globalData, new (globalData) JSString(globalData, UString(UStringImpl::create(s.rep(), offset, length)), JSString::HasOtherOwner)); } inline JSString* jsOwnedString(JSGlobalData* globalData, const UString& s) diff --git a/JavaScriptCore/runtime/JSVariableObject.h b/JavaScriptCore/runtime/JSVariableObject.h index 6c679ce..f2efcdf 100644 --- a/JavaScriptCore/runtime/JSVariableObject.h +++ b/JavaScriptCore/runtime/JSVariableObject.h @@ -52,7 +52,7 @@ namespace JSC { virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties); virtual bool isVariableObject() const; - virtual bool isDynamicScope() const = 0; + virtual bool isDynamicScope(bool& requiresDynamicChecks) const = 0; Register& registerAt(int index) const { return d->registers[index]; } diff --git a/JavaScriptCore/runtime/NumberPrototype.cpp b/JavaScriptCore/runtime/NumberPrototype.cpp index 5680eb1..7326b9d 100644 --- a/JavaScriptCore/runtime/NumberPrototype.cpp +++ b/JavaScriptCore/runtime/NumberPrototype.cpp @@ -143,15 +143,34 @@ JSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec, JSObject*, JSValu if (!v) return throwError(exec, TypeError); - double radixAsDouble = args.at(0).toInteger(exec); // nan -> 0 - if (radixAsDouble == 10 || args.at(0).isUndefined()) + JSValue radixValue = args.at(0); + int radix; + if (radixValue.isInt32()) + radix = radixValue.asInt32(); + else if (radixValue.isUndefined()) + radix = 10; + else + radix = static_cast<int>(radixValue.toInteger(exec)); // nan -> 0 + + if (radix == 10) return jsString(exec, v.toString(exec)); - if (radixAsDouble < 2 || radixAsDouble > 36) + static const char* const digits = "0123456789abcdefghijklmnopqrstuvwxyz"; + + // Fast path for number to character conversion. + if (radix == 36) { + if (v.isInt32()) { + int x = v.asInt32(); + if (static_cast<unsigned>(x) < 36) { // Exclude negatives + JSGlobalData* globalData = &exec->globalData(); + return globalData->smallStrings.singleCharacterString(globalData, digits[x]); + } + } + } + + if (radix < 2 || radix > 36) return throwError(exec, RangeError, "toString() radix argument must be between 2 and 36"); - int radix = static_cast<int>(radixAsDouble); - const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; // INT_MAX results in 1024 characters left of the dot with radix 2 // give the same space on the right side. safety checks are in place // unless someone finds a precise rule. diff --git a/JavaScriptCore/runtime/Operations.h b/JavaScriptCore/runtime/Operations.h index cc0d603..1228902 100644 --- a/JavaScriptCore/runtime/Operations.h +++ b/JavaScriptCore/runtime/Operations.h @@ -46,7 +46,7 @@ namespace JSC { if ((length1 + length2) < length1) return throwOutOfMemoryError(exec); - unsigned fiberCount = s1->fiberCount() + s2->fiberCount(); + unsigned fiberCount = s1->size() + s2->size(); JSGlobalData* globalData = &exec->globalData(); if (fiberCount <= JSString::s_maxInternalRopeLength) @@ -71,7 +71,7 @@ namespace JSC { if ((length1 + length2) < length1) return throwOutOfMemoryError(exec); - unsigned fiberCount = 1 + s2->fiberCount(); + unsigned fiberCount = 1 + s2->size(); JSGlobalData* globalData = &exec->globalData(); if (fiberCount <= JSString::s_maxInternalRopeLength) @@ -96,7 +96,7 @@ namespace JSC { if ((length1 + length2) < length1) return throwOutOfMemoryError(exec); - unsigned fiberCount = s1->fiberCount() + 1; + unsigned fiberCount = s1->size() + 1; JSGlobalData* globalData = &exec->globalData(); if (fiberCount <= JSString::s_maxInternalRopeLength) @@ -110,6 +110,42 @@ namespace JSC { return new (globalData) JSString(globalData, ropeBuilder.release()); } + ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, const UString& u2) + { + unsigned length1 = u1.size(); + if (!length1) + return jsString(exec, u2); + unsigned length2 = u2.size(); + if (!length2) + return jsString(exec, u1); + if ((length1 + length2) < length1) + return throwOutOfMemoryError(exec); + + JSGlobalData* globalData = &exec->globalData(); + return new (globalData) JSString(globalData, u1, u2); + } + + ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, const UString& u2, const UString& u3) + { + unsigned length1 = u1.size(); + unsigned length2 = u2.size(); + unsigned length3 = u3.size(); + if (!length1) + return jsString(exec, u2, u3); + if (!length2) + return jsString(exec, u1, u3); + if (!length3) + return jsString(exec, u1, u2); + + if ((length1 + length2) < length1) + return throwOutOfMemoryError(exec); + if ((length1 + length2 + length3) < length3) + return throwOutOfMemoryError(exec); + + JSGlobalData* globalData = &exec->globalData(); + return new (globalData) JSString(globalData, u1, u2, u3); + } + ALWAYS_INLINE JSValue jsString(ExecState* exec, Register* strings, unsigned count) { ASSERT(count >= 3); @@ -118,7 +154,7 @@ namespace JSC { for (unsigned i = 0; i < count; ++i) { JSValue v = strings[i].jsValue(); if (LIKELY(v.isString())) - fiberCount += asString(v)->fiberCount(); + fiberCount += asString(v)->size(); else ++fiberCount; } @@ -157,13 +193,13 @@ namespace JSC { { unsigned fiberCount = 0; if (LIKELY(thisValue.isString())) - fiberCount += asString(thisValue)->fiberCount(); + fiberCount += asString(thisValue)->size(); else ++fiberCount; for (unsigned i = 0; i < args.size(); ++i) { JSValue v = args.at(i); if (LIKELY(v.isString())) - fiberCount += asString(v)->fiberCount(); + fiberCount += asString(v)->size(); else ++fiberCount; } diff --git a/JavaScriptCore/runtime/RegExp.cpp b/JavaScriptCore/runtime/RegExp.cpp index f097943..0780984 100644 --- a/JavaScriptCore/runtime/RegExp.cpp +++ b/JavaScriptCore/runtime/RegExp.cpp @@ -107,7 +107,7 @@ int RegExp::match(const UString& s, int startOffset, Vector<int, 32>* ovector) if (startOffset < 0) startOffset = 0; if (ovector) - ovector->clear(); + ovector->resize(0); if (static_cast<unsigned>(startOffset) > s.size() || s.isNull()) return -1; @@ -132,7 +132,6 @@ int RegExp::match(const UString& s, int startOffset, Vector<int, 32>* ovector) for (int j = 0; j < offsetVectorSize; ++j) offsetVector[j] = -1; - #if ENABLE(YARR_JIT) int result = Yarr::executeRegex(m_regExpJITCode, s.data(), startOffset, s.size(), offsetVector, offsetVectorSize); #else diff --git a/JavaScriptCore/runtime/RegExpConstructor.h b/JavaScriptCore/runtime/RegExpConstructor.h index 8f4be71..bb0671a 100644 --- a/JavaScriptCore/runtime/RegExpConstructor.h +++ b/JavaScriptCore/runtime/RegExpConstructor.h @@ -109,7 +109,7 @@ namespace JSC { expression matching through the performMatch function. We use cached results to calculate, e.g., RegExp.lastMatch and RegExp.leftParen. */ - inline void RegExpConstructor::performMatch(RegExp* r, const UString& s, int startOffset, int& position, int& length, int** ovector) + ALWAYS_INLINE void RegExpConstructor::performMatch(RegExp* r, const UString& s, int startOffset, int& position, int& length, int** ovector) { position = r->match(s, startOffset, &d->tempOvector()); diff --git a/JavaScriptCore/runtime/RopeImpl.cpp b/JavaScriptCore/runtime/RopeImpl.cpp index a3760e6..25b9848 100644 --- a/JavaScriptCore/runtime/RopeImpl.cpp +++ b/JavaScriptCore/runtime/RopeImpl.cpp @@ -30,9 +30,9 @@ namespace JSC { void RopeImpl::derefFibersNonRecursive(Vector<RopeImpl*, 32>& workQueue) { - unsigned length = fiberCount(); - for (unsigned i = 0; i < length; ++i) { - Fiber& fiber = fibers(i); + unsigned fiberCount = this->fiberCount(); + for (unsigned i = 0; i < fiberCount; ++i) { + Fiber& fiber = m_fibers[i]; if (isRope(fiber)) { RopeImpl* nextRope = static_cast<RopeImpl*>(fiber); if (nextRope->hasOneRef()) diff --git a/JavaScriptCore/runtime/RopeImpl.h b/JavaScriptCore/runtime/RopeImpl.h index 6fbc595..ac2b502 100644 --- a/JavaScriptCore/runtime/RopeImpl.h +++ b/JavaScriptCore/runtime/RopeImpl.h @@ -46,18 +46,6 @@ public: return 0; } - void initializeFiber(unsigned &index, Fiber fiber) - { - m_fibers[index++] = fiber; - fiber->ref(); - m_length += fiber->length(); - } - - unsigned fiberCount() { return m_fiberCount; } - Fiber& fibers(unsigned index) { return m_fibers[index]; } - - ALWAYS_INLINE void deref() { m_refCountAndFlags -= s_refCountIncrement; if (!(m_refCountAndFlags & s_refCountMask)) destructNonRecursive(); } - static bool isRope(Fiber fiber) { return !fiber->isStringImpl(); @@ -71,15 +59,36 @@ public: static_cast<UStringImpl*>(fiber)->deref(); } + void initializeFiber(unsigned &index, Fiber fiber) + { + m_fibers[index++] = fiber; + fiber->ref(); + m_length += fiber->length(); + } + + unsigned fiberCount() { return m_size; } + Fiber* fibers() { return m_fibers; } + + ALWAYS_INLINE void deref() + { + m_refCountAndFlags -= s_refCountIncrement; + if (!(m_refCountAndFlags & s_refCountMask)) + destructNonRecursive(); + } + private: - RopeImpl(unsigned fiberCount) : StringImplBase(ConstructNonStringImpl), m_fiberCount(fiberCount) {} + RopeImpl(unsigned fiberCount) + : StringImplBase(ConstructNonStringImpl) + , m_size(fiberCount) + { + } void destructNonRecursive(); void derefFibersNonRecursive(Vector<RopeImpl*, 32>& workQueue); bool hasOneRef() { return (m_refCountAndFlags & s_refCountMask) == s_refCountIncrement; } - unsigned m_fiberCount; + unsigned m_size; Fiber m_fibers[1]; }; diff --git a/JavaScriptCore/runtime/StringPrototype.cpp b/JavaScriptCore/runtime/StringPrototype.cpp index 345378e..b385e70 100644 --- a/JavaScriptCore/runtime/StringPrototype.cpp +++ b/JavaScriptCore/runtime/StringPrototype.cpp @@ -245,8 +245,7 @@ public: int length; }; -JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, JSString* sourceVal, const UString& source, const StringRange* substringRanges, int rangeCount, const UString* separators, int separatorCount); -JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, JSString* sourceVal, const UString& source, const StringRange* substringRanges, int rangeCount, const UString* separators, int separatorCount) +static ALWAYS_INLINE JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, JSString* sourceVal, const UString& source, const StringRange* substringRanges, int rangeCount, const UString* separators, int separatorCount) { if (rangeCount == 1 && separatorCount == 0) { int sourceSize = source.size(); @@ -288,35 +287,12 @@ JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, JSString* sourceVal, c return jsString(exec, impl); } -JSValue jsReplaceRange(ExecState* exec, const UString& source, int rangeStart, int rangeLength, const UString& replacement); -JSValue jsReplaceRange(ExecState* exec, const UString& source, int rangeStart, int rangeLength, const UString& replacement) -{ - int replacementLength = replacement.size(); - int totalLength = source.size() - rangeLength + replacementLength; - if (totalLength == 0) - return jsString(exec, ""); - - UChar* buffer; - PassRefPtr<UStringImpl> impl = UStringImpl::tryCreateUninitialized(totalLength, buffer); - if (!impl) - return throwOutOfMemoryError(exec); - - UStringImpl::copyChars(buffer, source.data(), rangeStart); - UStringImpl::copyChars(buffer + rangeStart, replacement.data(), replacementLength); - int rangeEnd = rangeStart + rangeLength; - UStringImpl::copyChars(buffer + rangeStart + replacementLength, source.data() + rangeEnd, source.size() - rangeEnd); - - return jsString(exec, impl); -} - JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { JSString* sourceVal = thisValue.toThisJSString(exec); - const UString& source = sourceVal->value(exec); - JSValue pattern = args.at(0); - JSValue replacement = args.at(1); + UString replacementString; CallData callData; CallType callType = replacement.getCallData(callData); @@ -324,6 +300,7 @@ JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue replacementString = replacement.toString(exec); if (pattern.inherits(&RegExpObject::info)) { + const UString& source = sourceVal->value(exec); RegExp* reg = asRegExpObject(pattern)->regExp(); bool global = reg->global(); @@ -370,7 +347,10 @@ JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue cachedCall.setThis(exec->globalThisValue()); JSValue result = cachedCall.call(); - replacements.append(result.toString(cachedCall.newCallFrame(exec))); + if (LIKELY(result.isString())) + replacements.append(asString(result)->value(exec)); + else + replacements.append(result.toString(cachedCall.newCallFrame(exec))); if (exec->hadException()) break; @@ -442,6 +422,10 @@ JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue // Not a regular expression, so treat the pattern as a string. UString patternString = pattern.toString(exec); + if (patternString.size() == 1 && callType == CallTypeNone) + return sourceVal->replaceCharacter(exec, patternString[0], replacementString); + + const UString& source = sourceVal->value(exec); unsigned matchPos = source.find(patternString); if (matchPos == UString::NotFound) @@ -456,9 +440,10 @@ JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue replacementString = call(exec, replacement, callType, callData, exec->globalThisValue(), args).toString(exec); } - - int ovector[2] = { matchPos, matchPos + matchLen }; - return jsReplaceRange(exec, source, matchPos, matchLen, substituteBackreferences(replacementString, source, ovector, 0)); + + size_t matchEnd = matchPos + matchLen; + int ovector[2] = { matchPos, matchEnd }; + return jsString(exec, source.substr(0, matchPos), substituteBackreferences(replacementString, source, ovector, 0), source.substr(matchEnd)); } JSValue JSC_HOST_CALL stringProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -768,21 +753,20 @@ JSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec, JSObject*, JSVal JSValue a1 = args.at(1); double start = a0.toNumber(exec); - double end = a1.toNumber(exec); - if (isnan(start)) - start = 0; - if (isnan(end)) - end = 0; - if (start < 0) + double end; + if (!(start >= 0)) // check for negative values or NaN start = 0; - if (end < 0) - end = 0; - if (start > len) + else if (start > len) start = len; - if (end > len) - end = len; if (a1.isUndefined()) end = len; + else { + end = a1.toNumber(exec); + if (!(end >= 0)) // check for negative values or NaN + end = 0; + else if (end > len) + end = len; + } if (start > end) { double temp = end; end = start; diff --git a/JavaScriptCore/runtime/UString.h b/JavaScriptCore/runtime/UString.h index da1065e..a97e0d7 100644 --- a/JavaScriptCore/runtime/UString.h +++ b/JavaScriptCore/runtime/UString.h @@ -146,6 +146,7 @@ namespace JSC { return m_rep->cost(); } + ALWAYS_INLINE ~UString() { } private: RefPtr<Rep> m_rep; @@ -334,7 +335,7 @@ namespace JSC { StringTypeAdapter<StringType2> adapter2(string2); StringTypeAdapter<StringType3> adapter3(string3); - UChar* buffer; + UChar* buffer = 0; bool overflow = false; unsigned length = adapter1.length(); sumWithOverflow(length, adapter2.length(), overflow); |