summaryrefslogtreecommitdiffstats
path: root/JavaScriptCore/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'JavaScriptCore/runtime')
-rw-r--r--JavaScriptCore/runtime/Arguments.h4
-rw-r--r--JavaScriptCore/runtime/ArrayPrototype.cpp41
-rw-r--r--JavaScriptCore/runtime/Collector.cpp5
-rw-r--r--JavaScriptCore/runtime/Collector.h1
-rw-r--r--JavaScriptCore/runtime/DatePrototype.cpp24
-rw-r--r--JavaScriptCore/runtime/Executable.cpp87
-rw-r--r--JavaScriptCore/runtime/Executable.h123
-rw-r--r--JavaScriptCore/runtime/JSActivation.cpp5
-rw-r--r--JavaScriptCore/runtime/JSActivation.h6
-rw-r--r--JavaScriptCore/runtime/JSCell.h7
-rw-r--r--JavaScriptCore/runtime/JSFunction.cpp10
-rw-r--r--JavaScriptCore/runtime/JSGlobalData.cpp2
-rw-r--r--JavaScriptCore/runtime/JSGlobalObject.cpp2
-rw-r--r--JavaScriptCore/runtime/JSGlobalObject.h2
-rw-r--r--JavaScriptCore/runtime/JSStaticScopeObject.cpp2
-rw-r--r--JavaScriptCore/runtime/JSStaticScopeObject.h2
-rw-r--r--JavaScriptCore/runtime/JSString.cpp55
-rw-r--r--JavaScriptCore/runtime/JSString.h110
-rw-r--r--JavaScriptCore/runtime/JSVariableObject.h2
-rw-r--r--JavaScriptCore/runtime/NumberPrototype.cpp29
-rw-r--r--JavaScriptCore/runtime/Operations.h48
-rw-r--r--JavaScriptCore/runtime/RegExp.cpp3
-rw-r--r--JavaScriptCore/runtime/RegExpConstructor.h2
-rw-r--r--JavaScriptCore/runtime/RopeImpl.cpp6
-rw-r--r--JavaScriptCore/runtime/RopeImpl.h37
-rw-r--r--JavaScriptCore/runtime/StringPrototype.cpp66
-rw-r--r--JavaScriptCore/runtime/UString.h3
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);