diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:41 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:41 -0800 |
commit | 648161bb0edfc3d43db63caed5cc5213bc6cb78f (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /JavaScriptCore/kjs | |
parent | a65af38181ac7d34544586bdb5cd004de93897ad (diff) | |
download | external_webkit-648161bb0edfc3d43db63caed5cc5213bc6cb78f.zip external_webkit-648161bb0edfc3d43db63caed5cc5213bc6cb78f.tar.gz external_webkit-648161bb0edfc3d43db63caed5cc5213bc6cb78f.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'JavaScriptCore/kjs')
37 files changed, 0 insertions, 16964 deletions
diff --git a/JavaScriptCore/kjs/LabelScope.h b/JavaScriptCore/kjs/LabelScope.h deleted file mode 100644 index 8c30be5..0000000 --- a/JavaScriptCore/kjs/LabelScope.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2008 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef LabelScope_h -#define LabelScope_h - -#include <wtf/PassRefPtr.h> -#include "LabelID.h" - -namespace JSC { - - class Identifier; - - class LabelScope { - public: - enum Type { Loop, Switch, NamedLabel }; - - LabelScope(Type type, const Identifier* name, int scopeDepth, PassRefPtr<LabelID> breakTarget, PassRefPtr<LabelID> continueTarget) - : m_refCount(0) - , m_type(type) - , m_name(name) - , m_scopeDepth(scopeDepth) - , m_breakTarget(breakTarget) - , m_continueTarget(continueTarget) - { - } - - // It doesn't really make sense to copy a LabelScope, but we need this copy - // constructor to support moving LabelScopes in a Vector. - - LabelScope(const LabelScope& other) - : m_refCount(other.m_refCount) - , m_type(other.m_type) - , m_name(other.m_name) - , m_scopeDepth(other.m_scopeDepth) - , m_breakTarget(other.m_breakTarget) - , m_continueTarget(other.m_continueTarget) - { - } - - void ref() { ++m_refCount; } - void deref() - { - --m_refCount; - ASSERT(m_refCount >= 0); - } - int refCount() const { return m_refCount; } - - LabelID* breakTarget() const { return m_breakTarget.get(); } - LabelID* continueTarget() const { return m_continueTarget.get(); } - - Type type() const { return m_type; } - const Identifier* name() const { return m_name; } - int scopeDepth() const { return m_scopeDepth; } - - private: - int m_refCount; - Type m_type; - const Identifier* m_name; - int m_scopeDepth; - RefPtr<LabelID> m_breakTarget; - RefPtr<LabelID> m_continueTarget; - }; - -} // namespace JSC - -#endif // LabelScope_h diff --git a/JavaScriptCore/kjs/NodeInfo.h b/JavaScriptCore/kjs/NodeInfo.h deleted file mode 100644 index 2d11dc2..0000000 --- a/JavaScriptCore/kjs/NodeInfo.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2007 Apple Inc. 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 - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef NodeInfo_h -#define NodeInfo_h - -#include "nodes.h" -#include "Parser.h" - -namespace JSC { - - template <typename T> struct NodeInfo { - T m_node; - CodeFeatures m_features; - int m_numConstants; - }; - - typedef NodeInfo<FuncDeclNode*> FuncDeclNodeInfo; - typedef NodeInfo<FuncExprNode*> FuncExprNodeInfo; - typedef NodeInfo<ExpressionNode*> ExpressionNodeInfo; - typedef NodeInfo<ArgumentsNode*> ArgumentsNodeInfo; - typedef NodeInfo<ConstDeclNode*> ConstDeclNodeInfo; - typedef NodeInfo<PropertyNode*> PropertyNodeInfo; - typedef NodeInfo<PropertyList> PropertyListInfo; - typedef NodeInfo<ElementList> ElementListInfo; - typedef NodeInfo<ArgumentList> ArgumentListInfo; - - template <typename T> struct NodeDeclarationInfo { - T m_node; - ParserRefCountedData<DeclarationStacks::VarStack>* m_varDeclarations; - ParserRefCountedData<DeclarationStacks::FunctionStack>* m_funcDeclarations; - CodeFeatures m_features; - int m_numConstants; - }; - - typedef NodeDeclarationInfo<StatementNode*> StatementNodeInfo; - typedef NodeDeclarationInfo<CaseBlockNode*> CaseBlockNodeInfo; - typedef NodeDeclarationInfo<CaseClauseNode*> CaseClauseNodeInfo; - typedef NodeDeclarationInfo<SourceElements*> SourceElementsInfo; - typedef NodeDeclarationInfo<ClauseList> ClauseListInfo; - typedef NodeDeclarationInfo<ExpressionNode*> VarDeclListInfo; - typedef NodeDeclarationInfo<ConstDeclList> ConstDeclListInfo; - typedef NodeDeclarationInfo<ParameterList> ParameterListInfo; - -} // namespace JSC - -#endif // NodeInfo_h diff --git a/JavaScriptCore/kjs/Parser.cpp b/JavaScriptCore/kjs/Parser.cpp deleted file mode 100644 index 26773e8..0000000 --- a/JavaScriptCore/kjs/Parser.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) - * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2006, 2007, 2008 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "Parser.h" - -#include "Debugger.h" -#include "lexer.h" -#include <wtf/HashSet.h> -#include <wtf/Vector.h> - -extern int kjsyyparse(void*); - -namespace JSC { - -void Parser::parse(JSGlobalData* globalData, int* errLine, UString* errMsg) -{ - ASSERT(!m_sourceElements); - - int defaultErrLine; - UString defaultErrMsg; - - if (!errLine) - errLine = &defaultErrLine; - if (!errMsg) - errMsg = &defaultErrMsg; - - *errLine = -1; - *errMsg = 0; - - Lexer& lexer = *globalData->lexer; - lexer.setCode(*m_source); - - int parseError = kjsyyparse(globalData); - bool lexError = lexer.sawError(); - lexer.clear(); - - ParserRefCounted::deleteNewObjects(globalData); - - if (parseError || lexError) { - *errLine = lexer.lineNo(); - *errMsg = "Parse error"; - m_sourceElements.clear(); - } -} - -void Parser::didFinishParsing(SourceElements* sourceElements, ParserRefCountedData<DeclarationStacks::VarStack>* varStack, - ParserRefCountedData<DeclarationStacks::FunctionStack>* funcStack, CodeFeatures features, int lastLine, int numConstants) -{ - m_sourceElements = sourceElements; - m_varDeclarations = varStack; - m_funcDeclarations = funcStack; - m_features = features; - m_lastLine = lastLine; - m_numConstants = numConstants; -} - -} // namespace JSC diff --git a/JavaScriptCore/kjs/Parser.h b/JavaScriptCore/kjs/Parser.h deleted file mode 100644 index c2f55d7..0000000 --- a/JavaScriptCore/kjs/Parser.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) - * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2006, 2007, 2008 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#ifndef Parser_h -#define Parser_h - -#include "SourceProvider.h" -#include "Debugger.h" -#include "nodes.h" -#include <wtf/Forward.h> -#include <wtf/Noncopyable.h> -#include <wtf/OwnPtr.h> -#include <wtf/RefPtr.h> - -namespace JSC { - - class FunctionBodyNode; - class ProgramNode; - class UString; - - template <typename T> - struct ParserRefCountedData : ParserRefCounted { - ParserRefCountedData(JSGlobalData* globalData) - : ParserRefCounted(globalData) - { - } - - T data; - }; - - class Parser : Noncopyable { - public: - template <class ParsedNode> PassRefPtr<ParsedNode> parse(ExecState*, Debugger*, const SourceCode&, int* errLine = 0, UString* errMsg = 0); - - void didFinishParsing(SourceElements*, ParserRefCountedData<DeclarationStacks::VarStack>*, - ParserRefCountedData<DeclarationStacks::FunctionStack>*, CodeFeatures features, int lastLine, int numConstants); - - private: - void parse(JSGlobalData*, int* errLine, UString* errMsg); - - const SourceCode* m_source; - RefPtr<SourceElements> m_sourceElements; - RefPtr<ParserRefCountedData<DeclarationStacks::VarStack> > m_varDeclarations; - RefPtr<ParserRefCountedData<DeclarationStacks::FunctionStack> > m_funcDeclarations; - CodeFeatures m_features; - int m_lastLine; - int m_numConstants; - }; - - template <class ParsedNode> PassRefPtr<ParsedNode> Parser::parse(ExecState* exec, Debugger* debugger, const SourceCode& source, int* errLine, UString* errMsg) - { - m_source = &source; - parse(&exec->globalData(), errLine, errMsg); - RefPtr<ParsedNode> result; - if (m_sourceElements) { - result = ParsedNode::create(&exec->globalData(), - m_sourceElements.get(), - m_varDeclarations ? &m_varDeclarations->data : 0, - m_funcDeclarations ? &m_funcDeclarations->data : 0, - *m_source, - m_features, - m_numConstants); - result->setLoc(m_source->firstLine(), m_lastLine); - } - - m_source = 0; - m_sourceElements = 0; - m_varDeclarations = 0; - m_funcDeclarations = 0; - - if (debugger) - debugger->sourceParsed(exec, source, *errLine, *errMsg); - return result.release(); - } - -} // namespace JSC - -#endif // Parser_h diff --git a/JavaScriptCore/kjs/ResultType.h b/JavaScriptCore/kjs/ResultType.h deleted file mode 100644 index f838ce0..0000000 --- a/JavaScriptCore/kjs/ResultType.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (C) 2008 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef ResultType_h -#define ResultType_h - -namespace JSC { - - struct ResultType { - friend struct OperandTypes; - - typedef char Type; - static const Type TypeReusable = 1; - - static const Type TypeMaybeNumber = 2; - static const Type TypeMaybeString = 4; - static const Type TypeMaybeNull = 8; - static const Type TypeMaybeBool = 16; - static const Type TypeMaybeOther = 32; - - static const Type TypeReusableNumber = 3; - static const Type TypeStringOrReusableNumber = 4; - - explicit ResultType(Type type) - : m_type(type) - { - } - - bool isReusable() - { - return (m_type & TypeReusable); - } - - bool isReusableNumber() - { - return isReusable() && definitelyIsNumber(); - } - - bool definitelyIsNumber() - { - return ((m_type & ~TypeReusable) == TypeMaybeNumber); - } - - bool isNotNumber() - { - return ((m_type & TypeMaybeNumber) == 0); - } - - bool mightBeNumber() - { - return !isNotNumber(); - } - - int toInt() - { - return static_cast<int>(m_type); - } - - static ResultType nullType() - { - return ResultType(TypeMaybeNull); - } - - static ResultType boolean() - { - return ResultType(TypeMaybeBool); - } - - static ResultType constNumber() - { - return ResultType(TypeMaybeNumber); - } - - static ResultType reusableNumber() - { - return ResultType(TypeReusable | TypeMaybeNumber); - } - - static ResultType reusableNumberOrString() - { - return ResultType(TypeReusable | TypeMaybeNumber | TypeMaybeString); - } - - static ResultType string() - { - return ResultType(TypeMaybeString); - } - - static ResultType unknown() - { - return ResultType(TypeMaybeNumber | TypeMaybeString | TypeMaybeNull | TypeMaybeBool | TypeMaybeOther); - } - - static ResultType forAdd(ResultType op1, ResultType op2) - { - if (op1.definitelyIsNumber() && op2.definitelyIsNumber()) - return reusableNumber(); - if (op1.isNotNumber() || op2.isNotNumber()) - return string(); - return reusableNumberOrString(); - } - - private: - Type m_type; - }; - - struct OperandTypes - { - OperandTypes(ResultType first = ResultType::unknown(), ResultType second = ResultType::unknown()) - { - m_u.rds.first = first.m_type; - m_u.rds.second = second.m_type; - } - - union { - struct { - ResultType::Type first; - ResultType::Type second; - } rds; - int i; - } m_u; - - ResultType first() - { - return ResultType(m_u.rds.first); - } - - ResultType second() - { - return ResultType(m_u.rds.second); - } - - int toInt() - { - return m_u.i; - } - static OperandTypes fromInt(int value) - { - OperandTypes types; - types.m_u.i = value; - return types; - } - }; - -} // namespace JSC - -#endif // ResultType_h diff --git a/JavaScriptCore/kjs/Shell.cpp b/JavaScriptCore/kjs/Shell.cpp deleted file mode 100644 index f35679e..0000000 --- a/JavaScriptCore/kjs/Shell.cpp +++ /dev/null @@ -1,501 +0,0 @@ -/* - * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2006 Bjoern Graf (bjoern.graf@gmail.com) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" - -#include "CodeGenerator.h" -#include "InitializeThreading.h" -#include "JSArray.h" -#include "JSLock.h" -#include "PrototypeFunction.h" -#include "SamplingTool.h" -#include "completion.h" -#include "interpreter.h" -#include <math.h> -#include <stdio.h> -#include <string.h> - -#if !PLATFORM(WIN_OS) -#include <unistd.h> -#endif - -#if HAVE(READLINE) -#include <readline/history.h> -#include <readline/readline.h> -#endif - -#if HAVE(SYS_TIME_H) -#include <sys/time.h> -#endif - -#if PLATFORM(UNIX) -#include <signal.h> -#endif - -#if COMPILER(MSVC) -#include <crtdbg.h> -#include <windows.h> -#endif - -#if PLATFORM(QT) -#include <QCoreApplication> -#include <QDateTime> -#endif - -using namespace JSC; -using namespace WTF; - -static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>& buffer); - -static JSValue* functionPrint(ExecState*, JSObject*, JSValue*, const ArgList&); -static JSValue* functionDebug(ExecState*, JSObject*, JSValue*, const ArgList&); -static JSValue* functionGC(ExecState*, JSObject*, JSValue*, const ArgList&); -static JSValue* functionVersion(ExecState*, JSObject*, JSValue*, const ArgList&); -static JSValue* functionRun(ExecState*, JSObject*, JSValue*, const ArgList&); -static JSValue* functionLoad(ExecState*, JSObject*, JSValue*, const ArgList&); -static JSValue* functionReadline(ExecState*, JSObject*, JSValue*, const ArgList&); -static JSValue* functionQuit(ExecState*, JSObject*, JSValue*, const ArgList&); - -struct Options { - Options() - : interactive(false) - , prettyPrint(false) - , dump(false) - { - } - - bool interactive; - bool prettyPrint; - bool dump; - Vector<UString> fileNames; - Vector<UString> arguments; -}; - -static const char interactivePrompt[] = "> "; -static const UString interpreterName("Interpreter"); - -class StopWatch { -public: - void start(); - void stop(); - long getElapsedMS(); // call stop() first - -private: -#if PLATFORM(QT) - uint m_startTime; - uint m_stopTime; -#elif PLATFORM(WIN_OS) - DWORD m_startTime; - DWORD m_stopTime; -#else - // Windows does not have timeval, disabling this class for now (bug 7399) - timeval m_startTime; - timeval m_stopTime; -#endif -}; - -void StopWatch::start() -{ -#if PLATFORM(QT) - QDateTime t = QDateTime::currentDateTime(); - m_startTime = t.toTime_t() * 1000 + t.time().msec(); -#elif PLATFORM(WIN_OS) - m_startTime = timeGetTime(); -#else - gettimeofday(&m_startTime, 0); -#endif -} - -void StopWatch::stop() -{ -#if PLATFORM(QT) - QDateTime t = QDateTime::currentDateTime(); - m_stopTime = t.toTime_t() * 1000 + t.time().msec(); -#elif PLATFORM(WIN_OS) - m_stopTime = timeGetTime(); -#else - gettimeofday(&m_stopTime, 0); -#endif -} - -long StopWatch::getElapsedMS() -{ -#if PLATFORM(WIN_OS) || PLATFORM(QT) - return m_stopTime - m_startTime; -#else - timeval elapsedTime; - timersub(&m_stopTime, &m_startTime, &elapsedTime); - - return elapsedTime.tv_sec * 1000 + lroundf(elapsedTime.tv_usec / 1000.0f); -#endif -} - -class GlobalObject : public JSGlobalObject { -public: - GlobalObject(const Vector<UString>& arguments); - virtual UString className() const { return "global"; } -}; -COMPILE_ASSERT(!IsInteger<GlobalObject>::value, WTF_IsInteger_GlobalObject_false); -ASSERT_CLASS_FITS_IN_CELL(GlobalObject); - -GlobalObject::GlobalObject(const Vector<UString>& arguments) - : JSGlobalObject() -{ - putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "debug"), functionDebug)); - putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "print"), functionPrint)); - putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 0, Identifier(globalExec(), "quit"), functionQuit)); - putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 0, Identifier(globalExec(), "gc"), functionGC)); - putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "version"), functionVersion)); - putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "run"), functionRun)); - putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "load"), functionLoad)); - putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 0, Identifier(globalExec(), "readline"), functionReadline)); - - JSObject* array = constructEmptyArray(globalExec()); - for (size_t i = 0; i < arguments.size(); ++i) - array->put(globalExec(), i, jsString(globalExec(), arguments[i])); - putDirect(Identifier(globalExec(), "arguments"), array); -} - -JSValue* functionPrint(ExecState* exec, JSObject*, JSValue*, const ArgList& args) -{ - for (unsigned i = 0; i < args.size(); ++i) { - if (i != 0) - putchar(' '); - - printf("%s", args.at(exec, i)->toString(exec).UTF8String().c_str()); - } - - putchar('\n'); - fflush(stdout); - return jsUndefined(); -} - -JSValue* functionDebug(ExecState* exec, JSObject*, JSValue*, const ArgList& args) -{ - fprintf(stderr, "--> %s\n", args.at(exec, 0)->toString(exec).UTF8String().c_str()); - return jsUndefined(); -} - -JSValue* functionGC(ExecState* exec, JSObject*, JSValue*, const ArgList&) -{ - JSLock lock(false); - exec->heap()->collect(); - return jsUndefined(); -} - -JSValue* functionVersion(ExecState*, JSObject*, JSValue*, const ArgList&) -{ - // We need this function for compatibility with the Mozilla JS tests but for now - // we don't actually do any version-specific handling - return jsUndefined(); -} - -JSValue* functionRun(ExecState* exec, JSObject*, JSValue*, const ArgList& args) -{ - StopWatch stopWatch; - UString fileName = args.at(exec, 0)->toString(exec); - Vector<char> script; - if (!fillBufferWithContentsOfFile(fileName, script)) - return throwError(exec, GeneralError, "Could not open file."); - - JSGlobalObject* globalObject = exec->lexicalGlobalObject(); - - stopWatch.start(); - Interpreter::evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(script.data(), fileName)); - stopWatch.stop(); - - return jsNumber(globalObject->globalExec(), stopWatch.getElapsedMS()); -} - -JSValue* functionLoad(ExecState* exec, JSObject*, JSValue*, const ArgList& args) -{ - UString fileName = args.at(exec, 0)->toString(exec); - Vector<char> script; - if (!fillBufferWithContentsOfFile(fileName, script)) - return throwError(exec, GeneralError, "Could not open file."); - - JSGlobalObject* globalObject = exec->lexicalGlobalObject(); - Interpreter::evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(script.data(), fileName)); - - return jsUndefined(); -} - -JSValue* functionReadline(ExecState* exec, JSObject*, JSValue*, const ArgList&) -{ - Vector<char, 256> line; - int c; - while ((c = getchar()) != EOF) { - // FIXME: Should we also break on \r? - if (c == '\n') - break; - line.append(c); - } - line.append('\0'); - return jsString(exec, line.data()); -} - -JSValue* functionQuit(ExecState*, JSObject*, JSValue*, const ArgList&) -{ - exit(0); -#if !COMPILER(MSVC) - // MSVC knows that exit(0) never returns, so it flags this return statement as unreachable. - return jsUndefined(); -#endif -} - -// Use SEH for Release builds only to get rid of the crash report dialog -// (luckily the same tests fail in Release and Debug builds so far). Need to -// be in a separate main function because the jscmain function requires object -// unwinding. - -#if COMPILER(MSVC) && !defined(_DEBUG) -#define TRY __try { -#define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; } -#else -#define TRY -#define EXCEPT(x) -#endif - -int jscmain(int argc, char** argv, JSGlobalData*); - -int main(int argc, char** argv) -{ -#if defined(_DEBUG) && PLATFORM(WIN_OS) - _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); - _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); - _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); - _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); - _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); - _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); -#endif - -#if PLATFORM(QT) - QCoreApplication app(argc, argv); -#endif - - int res = 0; - TRY - res = jscmain(argc, argv, JSGlobalData::create().releaseRef()); - EXCEPT(res = 3) - return res; -} - -static bool prettyPrintScript(ExecState* exec, const UString& fileName, const Vector<char>& script) -{ - int errLine = 0; - UString errMsg; - RefPtr<ProgramNode> programNode = exec->globalData().parser->parse<ProgramNode>(exec, exec->dynamicGlobalObject()->debugger(), makeSource(script.data(), fileName), &errLine, &errMsg); - if (!programNode) { - fprintf(stderr, "%s:%d: %s.\n", fileName.UTF8String().c_str(), errLine, errMsg.UTF8String().c_str()); - return false; - } - - printf("%s\n", programNode->toString().UTF8String().c_str()); - return true; -} - -static bool runWithScripts(GlobalObject* globalObject, const Vector<UString>& fileNames, bool prettyPrint, bool dump) -{ - Vector<char> script; - - if (dump) - CodeGenerator::setDumpsGeneratedCode(true); - -#if ENABLE(OPCODE_SAMPLING) - Machine* machine = globalObject->globalData()->machine; - machine->setSampler(new SamplingTool(machine)); -#endif - - bool success = true; - for (size_t i = 0; i < fileNames.size(); i++) { - UString fileName = fileNames[i]; - - if (!fillBufferWithContentsOfFile(fileName, script)) - return false; // fail early so we can catch missing files - - if (prettyPrint) - prettyPrintScript(globalObject->globalExec(), fileName, script); - else { -#if ENABLE(OPCODE_SAMPLING) - machine->sampler()->start(); -#endif - Completion completion = Interpreter::evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(script.data(), fileName)); - success = success && completion.complType() != Throw; - if (dump) { - if (completion.complType() == Throw) - printf("Exception: %s\n", completion.value()->toString(globalObject->globalExec()).ascii()); - else - printf("End: %s\n", completion.value()->toString(globalObject->globalExec()).ascii()); - } - - globalObject->globalExec()->clearException(); - -#if ENABLE(OPCODE_SAMPLING) - machine->sampler()->stop(); -#endif - } - } - -#if ENABLE(OPCODE_SAMPLING) - machine->sampler()->dump(globalObject->globalExec()); - delete machine->sampler(); -#endif - return success; -} - -static void runInteractive(GlobalObject* globalObject) -{ - while (true) { -#if HAVE(READLINE) - char* line = readline(interactivePrompt); - if (!line) - break; - if (line[0]) - add_history(line); - Completion completion = Interpreter::evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(line, interpreterName)); - free(line); -#else - puts(interactivePrompt); - Vector<char, 256> line; - int c; - while ((c = getchar()) != EOF) { - // FIXME: Should we also break on \r? - if (c == '\n') - break; - line.append(c); - } - line.append('\0'); - Completion completion = Interpreter::evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(line.data(), interpreterName)); -#endif - if (completion.complType() == Throw) - printf("Exception: %s\n", completion.value()->toString(globalObject->globalExec()).ascii()); - else - printf("%s\n", completion.value()->toString(globalObject->globalExec()).UTF8String().c_str()); - - globalObject->globalExec()->clearException(); - } - printf("\n"); -} - -static void printUsageStatement() -{ - fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n"); - fprintf(stderr, " -d Dumps bytecode (debug builds only)\n"); - fprintf(stderr, " -f Specifies a source file (deprecated)\n"); - fprintf(stderr, " -h|--help Prints this help message\n"); - fprintf(stderr, " -i Enables interactive mode (default if no files are specified)\n"); - fprintf(stderr, " -p Prints formatted source code\n"); - fprintf(stderr, " -s Installs signal handlers that exit on a crash (Unix platforms only)\n"); - exit(-1); -} - -static void parseArguments(int argc, char** argv, Options& options) -{ - int i = 1; - for (; i < argc; ++i) { - const char* arg = argv[i]; - if (strcmp(arg, "-f") == 0) { - if (++i == argc) - printUsageStatement(); - options.fileNames.append(argv[i]); - continue; - } - if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) { - printUsageStatement(); - } - if (strcmp(arg, "-i") == 0) { - options.interactive = true; - continue; - } - if (strcmp(arg, "-p") == 0) { - options.prettyPrint = true; - continue; - } - if (strcmp(arg, "-d") == 0) { - options.dump = true; - continue; - } - if (strcmp(arg, "-s") == 0) { -#if PLATFORM(UNIX) - signal(SIGILL, _exit); - signal(SIGFPE, _exit); - signal(SIGBUS, _exit); - signal(SIGSEGV, _exit); -#endif - continue; - } - if (strcmp(arg, "--") == 0) { - ++i; - break; - } - options.fileNames.append(argv[i]); - } - - if (options.fileNames.isEmpty()) - options.interactive = true; - - for (; i < argc; ++i) - options.arguments.append(argv[i]); -} - -int jscmain(int argc, char** argv, JSGlobalData* globalData) -{ - JSC::initializeThreading(); - - JSLock lock(false); - - Options options; - parseArguments(argc, argv, options); - - GlobalObject* globalObject = new (globalData) GlobalObject(options.arguments); - bool success = runWithScripts(globalObject, options.fileNames, options.prettyPrint, options.dump); - if (options.interactive && success) - runInteractive(globalObject); - - return success ? 0 : 3; -} - -static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>& buffer) -{ - FILE* f = fopen(fileName.UTF8String().c_str(), "r"); - if (!f) { - fprintf(stderr, "Could not open file: %s\n", fileName.UTF8String().c_str()); - return false; - } - - size_t buffer_size = 0; - size_t buffer_capacity = 1024; - - buffer.resize(buffer_capacity); - - while (!feof(f) && !ferror(f)) { - buffer_size += fread(buffer.data() + buffer_size, 1, buffer_capacity - buffer_size, f); - if (buffer_size == buffer_capacity) { // guarantees space for trailing '\0' - buffer_capacity *= 2; - buffer.resize(buffer_capacity); - } - } - fclose(f); - buffer[buffer_size] = '\0'; - - return true; -} diff --git a/JavaScriptCore/kjs/SourceCode.h b/JavaScriptCore/kjs/SourceCode.h deleted file mode 100644 index 2840161..0000000 --- a/JavaScriptCore/kjs/SourceCode.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2008 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SourceCode_h -#define SourceCode_h - -#include "SourceProvider.h" -#include <wtf/RefPtr.h> - -namespace JSC { - - class SourceCode { - public: - SourceCode() - : m_startChar(0) - , m_endChar(0) - , m_firstLine(0) - { - } - - SourceCode(PassRefPtr<SourceProvider> provider, int firstLine = 1) - : m_provider(provider) - , m_startChar(0) - , m_endChar(m_provider->length()) - , m_firstLine(std::max(firstLine, 1)) - { - } - - SourceCode(PassRefPtr<SourceProvider> provider, int start, int end, int firstLine) - : m_provider(provider) - , m_startChar(start) - , m_endChar(end) - , m_firstLine(std::max(firstLine, 1)) - { - } - - UString toString() const - { - if (!m_provider) - return UString(); - return m_provider->getRange(m_startChar, m_endChar); - } - - bool isNull() const { return !m_provider; } - SourceProvider* provider() const { return m_provider.get(); } - int firstLine() const { return m_firstLine; } - int startOffset() const { return m_startChar; } - const UChar* data() const { return m_provider->data() + m_startChar; } - int length() const { return m_endChar - m_startChar; } - - private: - RefPtr<SourceProvider> m_provider; - int m_startChar; - int m_endChar; - int m_firstLine; - }; - - inline SourceCode makeSource(const UString& source, const UString& url = UString(), int firstLine = 1) - { - return SourceCode(UStringSourceProvider::create(source, url), firstLine); - } - -} // namespace JSC - -#endif // SourceCode_h diff --git a/JavaScriptCore/kjs/SourceProvider.h b/JavaScriptCore/kjs/SourceProvider.h deleted file mode 100644 index 755a10f..0000000 --- a/JavaScriptCore/kjs/SourceProvider.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2008 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SourceProvider_h -#define SourceProvider_h - -#include "ustring.h" -#include <wtf/RefCounted.h> - -namespace JSC { - - class SourceProvider : public RefCounted<SourceProvider> { - public: - SourceProvider(const UString& url) - : m_url(url) - { - } - virtual ~SourceProvider() { } - - virtual UString getRange(int start, int end) const = 0; - virtual const UChar* data() const = 0; - virtual int length() const = 0; - - const UString& url() { return m_url; } - intptr_t asID() { return reinterpret_cast<intptr_t>(this); } - - private: - UString m_url; - }; - - class UStringSourceProvider : public SourceProvider { - public: - static PassRefPtr<UStringSourceProvider> create(const UString& source, const UString& url) - { - return adoptRef(new UStringSourceProvider(source, url)); - } - - UString getRange(int start, int end) const { return m_source.substr(start, end - start); } - const UChar* data() const { return m_source.data(); } - int length() const { return m_source.size(); } - - private: - UStringSourceProvider(const UString& source, const UString& url) - : SourceProvider(url) - , m_source(source) - { - } - - UString m_source; - }; - -} // namespace JSC - -#endif // SourceProvider_h diff --git a/JavaScriptCore/kjs/TypeInfo.h b/JavaScriptCore/kjs/TypeInfo.h deleted file mode 100644 index 4f0b16c..0000000 --- a/JavaScriptCore/kjs/TypeInfo.h +++ /dev/null @@ -1,63 +0,0 @@ -// -*- mode: c++; c-basic-offset: 4 -*- -/* - * Copyright (C) 2008 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TypeInfo_h -#define TypeInfo_h - -#include "JSType.h" - -namespace JSC { - - // WebCore uses MasqueradesAsUndefined to make document.all and style.filter undetectable. - static const unsigned MasqueradesAsUndefined = 1; - static const unsigned ImplementsHasInstance = 1 << 1; - static const unsigned OverridesHasInstance = 1 << 2; - static const unsigned NeedsThisConversion = 1 << 3; - static const unsigned HasStandardGetOwnPropertySlot = 1 << 4; - - class TypeInfo { - friend class CTI; - public: - TypeInfo(JSType type, unsigned flags = 0) : m_type(type), m_flags(flags) { } - - JSType type() const { return m_type; } - - bool masqueradesAsUndefined() const { return m_flags & MasqueradesAsUndefined; } - bool implementsHasInstance() const { return m_flags & ImplementsHasInstance; } - bool overridesHasInstance() const { return m_flags & OverridesHasInstance; } - bool needsThisConversion() const { return m_flags & NeedsThisConversion; } - bool hasStandardGetOwnPropertySlot() const { return m_flags & HasStandardGetOwnPropertySlot; } - - unsigned flags() const { return m_flags; } - - private: - JSType m_type; - unsigned m_flags; - }; - -} - -#endif // TypeInfo_h diff --git a/JavaScriptCore/kjs/collector.cpp b/JavaScriptCore/kjs/collector.cpp deleted file mode 100644 index 53e889e..0000000 --- a/JavaScriptCore/kjs/collector.cpp +++ /dev/null @@ -1,1094 +0,0 @@ -/* - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2007 Eric Seidel <eric@webkit.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "config.h" -#include "collector.h" - -#include "ArgList.h" -#include "CollectorHeapIterator.h" -#include "ExecState.h" -#include "JSGlobalObject.h" -#include "JSLock.h" -#include "JSString.h" -#include "JSValue.h" -#include "Machine.h" -#include "Tracing.h" -#include <algorithm> -#include <setjmp.h> -#include <stdlib.h> -#include <wtf/FastMalloc.h> -#include <wtf/HashCountedSet.h> -#include <wtf/UnusedParam.h> - -#if PLATFORM(DARWIN) - -#include <mach/mach_port.h> -#include <mach/mach_init.h> -#include <mach/task.h> -#include <mach/thread_act.h> -#include <mach/vm_map.h> - -#elif PLATFORM(WIN_OS) - -#include <windows.h> - -#elif PLATFORM(UNIX) - -#include <stdlib.h> -#include <sys/mman.h> -#include <unistd.h> - -#if PLATFORM(SOLARIS) -#include <thread.h> -#endif - -#if PLATFORM(LINUX) -#include <pthread.h> -#endif - -#if PLATFORM(OPENBSD) -#include <pthread.h> -#endif - -#if HAVE(PTHREAD_NP_H) -#include <pthread_np.h> -#endif - -#endif - -#define DEBUG_COLLECTOR 0 -#define COLLECT_ON_EVERY_ALLOCATION 0 - -using std::max; - -namespace JSC { - -// tunable parameters - -const size_t SPARE_EMPTY_BLOCKS = 2; -const size_t GROWTH_FACTOR = 2; -const size_t LOW_WATER_FACTOR = 4; -const size_t ALLOCATIONS_PER_COLLECTION = 4000; -// This value has to be a macro to be used in max() without introducing -// a PIC branch in Mach-O binaries, see <rdar://problem/5971391>. -#define MIN_ARRAY_SIZE (static_cast<size_t>(14)) - -static void freeHeap(CollectorHeap*); - -#if ENABLE(JSC_MULTIPLE_THREADS) - -#if PLATFORM(DARWIN) -typedef mach_port_t PlatformThread; -#elif PLATFORM(WIN_OS) -struct PlatformThread { - PlatformThread(DWORD _id, HANDLE _handle) : id(_id), handle(_handle) {} - DWORD id; - HANDLE handle; -}; -#endif - -class Heap::Thread { -public: - Thread(pthread_t pthread, const PlatformThread& platThread, void* base) - : posixThread(pthread) - , platformThread(platThread) - , stackBase(base) - { - } - - Thread* next; - pthread_t posixThread; - PlatformThread platformThread; - void* stackBase; -}; - -#endif - -Heap::Heap(JSGlobalData* globalData) - : m_markListSet(0) -#if ENABLE(JSC_MULTIPLE_THREADS) - , m_registeredThreads(0) -#endif - , m_globalData(globalData) -{ - ASSERT(globalData); - -#if ENABLE(JSC_MULTIPLE_THREADS) - int error = pthread_key_create(&m_currentThreadRegistrar, unregisterThread); - if (error) - CRASH(); -#endif - - memset(&primaryHeap, 0, sizeof(CollectorHeap)); - memset(&numberHeap, 0, sizeof(CollectorHeap)); -} - -Heap::~Heap() -{ - // The destroy function must already have been called, so assert this. - ASSERT(!m_globalData); -} - -void Heap::destroy() -{ - JSLock lock(false); - - if (!m_globalData) - return; - - // The global object is not GC protected at this point, so sweeping may delete it - // (and thus the global data) before other objects that may use the global data. - RefPtr<JSGlobalData> protect(m_globalData); - - delete m_markListSet; - m_markListSet = 0; - - sweep<PrimaryHeap>(); - // No need to sweep number heap, because the JSNumber destructor doesn't do anything. - - ASSERT(!primaryHeap.numLiveObjects); - - freeHeap(&primaryHeap); - freeHeap(&numberHeap); - -#if ENABLE(JSC_MULTIPLE_THREADS) -#ifndef NDEBUG - int error = -#endif - pthread_key_delete(m_currentThreadRegistrar); - ASSERT(!error); - - MutexLocker registeredThreadsLock(m_registeredThreadsMutex); - for (Heap::Thread* t = m_registeredThreads; t;) { - Heap::Thread* next = t->next; - delete t; - t = next; - } -#endif - - m_globalData = 0; -} - -template <HeapType heapType> -static NEVER_INLINE CollectorBlock* allocateBlock() -{ -#if PLATFORM(DARWIN) - vm_address_t address = 0; - // FIXME: tag the region as a JavaScriptCore heap when we get a registered VM tag: <rdar://problem/6054788>. - vm_map(current_task(), &address, BLOCK_SIZE, BLOCK_OFFSET_MASK, VM_FLAGS_ANYWHERE, MEMORY_OBJECT_NULL, 0, FALSE, VM_PROT_DEFAULT, VM_PROT_DEFAULT, VM_INHERIT_DEFAULT); -#elif PLATFORM(WIN_OS) - // windows virtual address granularity is naturally 64k - LPVOID address = VirtualAlloc(NULL, BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); -#elif HAVE(POSIX_MEMALIGN) - void* address; - posix_memalign(&address, BLOCK_SIZE, BLOCK_SIZE); - memset(address, 0, BLOCK_SIZE); -#else - -#if ENABLE(JSC_MULTIPLE_THREADS) -#error Need to initialize pagesize safely. -#endif - static size_t pagesize = getpagesize(); - - size_t extra = 0; - if (BLOCK_SIZE > pagesize) - extra = BLOCK_SIZE - pagesize; - - void* mmapResult = mmap(NULL, BLOCK_SIZE + extra, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); - uintptr_t address = reinterpret_cast<uintptr_t>(mmapResult); - - size_t adjust = 0; - if ((address & BLOCK_OFFSET_MASK) != 0) - adjust = BLOCK_SIZE - (address & BLOCK_OFFSET_MASK); - - if (adjust > 0) - munmap(reinterpret_cast<char*>(address), adjust); - - if (adjust < extra) - munmap(reinterpret_cast<char*>(address + adjust + BLOCK_SIZE), extra - adjust); - - address += adjust; - memset(reinterpret_cast<void*>(address), 0, BLOCK_SIZE); -#endif - reinterpret_cast<CollectorBlock*>(address)->type = heapType; - return reinterpret_cast<CollectorBlock*>(address); -} - -static void freeBlock(CollectorBlock* block) -{ -#if PLATFORM(DARWIN) - vm_deallocate(current_task(), reinterpret_cast<vm_address_t>(block), BLOCK_SIZE); -#elif PLATFORM(WIN_OS) - VirtualFree(block, 0, MEM_RELEASE); -#elif HAVE(POSIX_MEMALIGN) - free(block); -#else - munmap(reinterpret_cast<char*>(block), BLOCK_SIZE); -#endif -} - -static void freeHeap(CollectorHeap* heap) -{ - for (size_t i = 0; i < heap->usedBlocks; ++i) - if (heap->blocks[i]) - freeBlock(heap->blocks[i]); - fastFree(heap->blocks); - memset(heap, 0, sizeof(CollectorHeap)); -} - -void Heap::recordExtraCost(size_t cost) -{ - // Our frequency of garbage collection tries to balance memory use against speed - // by collecting based on the number of newly created values. However, for values - // that hold on to a great deal of memory that's not in the form of other JS values, - // that is not good enough - in some cases a lot of those objects can pile up and - // use crazy amounts of memory without a GC happening. So we track these extra - // memory costs. Only unusually large objects are noted, and we only keep track - // of this extra cost until the next GC. In garbage collected languages, most values - // are either very short lived temporaries, or have extremely long lifetimes. So - // if a large value survives one garbage collection, there is not much point to - // collecting more frequently as long as it stays alive. - // NOTE: we target the primaryHeap unconditionally as JSNumber doesn't modify cost - - primaryHeap.extraCost += cost; -} - -template <HeapType heapType> ALWAYS_INLINE void* Heap::heapAllocate(size_t s) -{ - typedef typename HeapConstants<heapType>::Block Block; - typedef typename HeapConstants<heapType>::Cell Cell; - - CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap; - ASSERT(JSLock::lockCount() > 0); - ASSERT(JSLock::currentThreadIsHoldingLock()); - ASSERT(s <= HeapConstants<heapType>::cellSize); - UNUSED_PARAM(s); // s is now only used for the above assert - - ASSERT(heap.operationInProgress == NoOperation); - ASSERT(heapType == PrimaryHeap || heap.extraCost == 0); - // FIXME: If another global variable access here doesn't hurt performance - // too much, we could abort() in NDEBUG builds, which could help ensure we - // don't spend any time debugging cases where we allocate inside an object's - // deallocation code. - - size_t numLiveObjects = heap.numLiveObjects; - size_t usedBlocks = heap.usedBlocks; - size_t i = heap.firstBlockWithPossibleSpace; - -#if COLLECT_ON_EVERY_ALLOCATION - collect(); -#endif - - // if we have a huge amount of extra cost, we'll try to collect even if we still have - // free cells left. - if (heapType == PrimaryHeap && heap.extraCost > ALLOCATIONS_PER_COLLECTION) { - size_t numLiveObjectsAtLastCollect = heap.numLiveObjectsAtLastCollect; - size_t numNewObjects = numLiveObjects - numLiveObjectsAtLastCollect; - const size_t newCost = numNewObjects + heap.extraCost; - if (newCost >= ALLOCATIONS_PER_COLLECTION && newCost >= numLiveObjectsAtLastCollect) - goto collect; - } - - ASSERT(heap.operationInProgress == NoOperation); -#ifndef NDEBUG - // FIXME: Consider doing this in NDEBUG builds too (see comment above). - heap.operationInProgress = Allocation; -#endif - -scan: - Block* targetBlock; - size_t targetBlockUsedCells; - if (i != usedBlocks) { - targetBlock = reinterpret_cast<Block*>(heap.blocks[i]); - targetBlockUsedCells = targetBlock->usedCells; - ASSERT(targetBlockUsedCells <= HeapConstants<heapType>::cellsPerBlock); - while (targetBlockUsedCells == HeapConstants<heapType>::cellsPerBlock) { - if (++i == usedBlocks) - goto collect; - targetBlock = reinterpret_cast<Block*>(heap.blocks[i]); - targetBlockUsedCells = targetBlock->usedCells; - ASSERT(targetBlockUsedCells <= HeapConstants<heapType>::cellsPerBlock); - } - heap.firstBlockWithPossibleSpace = i; - } else { - -collect: - size_t numLiveObjectsAtLastCollect = heap.numLiveObjectsAtLastCollect; - size_t numNewObjects = numLiveObjects - numLiveObjectsAtLastCollect; - const size_t newCost = numNewObjects + heap.extraCost; - - if (newCost >= ALLOCATIONS_PER_COLLECTION && newCost >= numLiveObjectsAtLastCollect) { -#ifndef NDEBUG - heap.operationInProgress = NoOperation; -#endif - bool collected = collect(); -#ifndef NDEBUG - heap.operationInProgress = Allocation; -#endif - if (collected) { - numLiveObjects = heap.numLiveObjects; - usedBlocks = heap.usedBlocks; - i = heap.firstBlockWithPossibleSpace; - goto scan; - } - } - - // didn't find a block, and GC didn't reclaim anything, need to allocate a new block - size_t numBlocks = heap.numBlocks; - if (usedBlocks == numBlocks) { - numBlocks = max(MIN_ARRAY_SIZE, numBlocks * GROWTH_FACTOR); - heap.numBlocks = numBlocks; - heap.blocks = static_cast<CollectorBlock**>(fastRealloc(heap.blocks, numBlocks * sizeof(CollectorBlock*))); - } - - targetBlock = reinterpret_cast<Block*>(allocateBlock<heapType>()); - targetBlock->freeList = targetBlock->cells; - targetBlock->heap = this; - targetBlockUsedCells = 0; - heap.blocks[usedBlocks] = reinterpret_cast<CollectorBlock*>(targetBlock); - heap.usedBlocks = usedBlocks + 1; - heap.firstBlockWithPossibleSpace = usedBlocks; - } - - // find a free spot in the block and detach it from the free list - Cell* newCell = targetBlock->freeList; - - // "next" field is a cell offset -- 0 means next cell, so a zeroed block is already initialized - targetBlock->freeList = (newCell + 1) + newCell->u.freeCell.next; - - targetBlock->usedCells = static_cast<uint32_t>(targetBlockUsedCells + 1); - heap.numLiveObjects = numLiveObjects + 1; - -#ifndef NDEBUG - // FIXME: Consider doing this in NDEBUG builds too (see comment above). - heap.operationInProgress = NoOperation; -#endif - - return newCell; -} - -void* Heap::allocate(size_t s) -{ - return heapAllocate<PrimaryHeap>(s); -} - -void* Heap::allocateNumber(size_t s) -{ - return heapAllocate<NumberHeap>(s); -} - -static inline void* currentThreadStackBase() -{ -#if PLATFORM(DARWIN) - pthread_t thread = pthread_self(); - return pthread_get_stackaddr_np(thread); -#elif PLATFORM(WIN_OS) && PLATFORM(X86) && COMPILER(MSVC) - // offset 0x18 from the FS segment register gives a pointer to - // the thread information block for the current thread - NT_TIB* pTib; - __asm { - MOV EAX, FS:[18h] - MOV pTib, EAX - } - return static_cast<void*>(pTib->StackBase); -#elif PLATFORM(WIN_OS) && PLATFORM(X86_64) && COMPILER(MSVC) - PNT_TIB64 pTib = reinterpret_cast<PNT_TIB64>(NtCurrentTeb()); - return reinterpret_cast<void*>(pTib->StackBase); -#elif PLATFORM(WIN_OS) && PLATFORM(X86) && COMPILER(GCC) - // offset 0x18 from the FS segment register gives a pointer to - // the thread information block for the current thread - NT_TIB* pTib; - asm ( "movl %%fs:0x18, %0\n" - : "=r" (pTib) - ); - return static_cast<void*>(pTib->StackBase); -#elif PLATFORM(SOLARIS) - stack_t s; - thr_stksegment(&s); - return s.ss_sp; -#elif PLATFORM(OPENBSD) - pthread_t thread = pthread_self(); - stack_t stack; - pthread_stackseg_np(thread, &stack); - return stack.ss_sp; -#elif PLATFORM(UNIX) - static void* stackBase = 0; - static size_t stackSize = 0; - static pthread_t stackThread; - pthread_t thread = pthread_self(); - if (stackBase == 0 || thread != stackThread) { - pthread_attr_t sattr; - pthread_attr_init(&sattr); -#if HAVE(PTHREAD_NP_H) - // e.g. on FreeBSD 5.4, neundorf@kde.org - pthread_attr_get_np(thread, &sattr); -#else - // FIXME: this function is non-portable; other POSIX systems may have different np alternatives - pthread_getattr_np(thread, &sattr); -#endif - int rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize); - (void)rc; // FIXME: Deal with error code somehow? Seems fatal. - ASSERT(stackBase); - pthread_attr_destroy(&sattr); - stackThread = thread; - } - return static_cast<char*>(stackBase) + stackSize; -#else -#error Need a way to get the stack base on this platform -#endif -} - -#if ENABLE(JSC_MULTIPLE_THREADS) - -static inline PlatformThread getCurrentPlatformThread() -{ -#if PLATFORM(DARWIN) - return pthread_mach_thread_np(pthread_self()); -#elif PLATFORM(WIN_OS) - HANDLE threadHandle = pthread_getw32threadhandle_np(pthread_self()); - return PlatformThread(GetCurrentThreadId(), threadHandle); -#endif -} - -void Heap::registerThread() -{ - if (pthread_getspecific(m_currentThreadRegistrar)) - return; - - pthread_setspecific(m_currentThreadRegistrar, this); - Heap::Thread* thread = new Heap::Thread(pthread_self(), getCurrentPlatformThread(), currentThreadStackBase()); - - MutexLocker lock(m_registeredThreadsMutex); - - thread->next = m_registeredThreads; - m_registeredThreads = thread; -} - -void Heap::unregisterThread(void* p) -{ - if (p) - static_cast<Heap*>(p)->unregisterThread(); -} - -void Heap::unregisterThread() -{ - pthread_t currentPosixThread = pthread_self(); - - MutexLocker lock(m_registeredThreadsMutex); - - if (pthread_equal(currentPosixThread, m_registeredThreads->posixThread)) { - Thread* t = m_registeredThreads; - m_registeredThreads = m_registeredThreads->next; - delete t; - } else { - Heap::Thread* last = m_registeredThreads; - Heap::Thread* t; - for (t = m_registeredThreads->next; t; t = t->next) { - if (pthread_equal(t->posixThread, currentPosixThread)) { - last->next = t->next; - break; - } - last = t; - } - ASSERT(t); // If t is NULL, we never found ourselves in the list. - delete t; - } -} - -#else // ENABLE(JSC_MULTIPLE_THREADS) - -void Heap::registerThread() -{ -} - -#endif - -#define IS_POINTER_ALIGNED(p) (((intptr_t)(p) & (sizeof(char*) - 1)) == 0) - -// cell size needs to be a power of two for this to be valid -#define IS_HALF_CELL_ALIGNED(p) (((intptr_t)(p) & (CELL_MASK >> 1)) == 0) - -void Heap::markConservatively(void* start, void* end) -{ - if (start > end) { - void* tmp = start; - start = end; - end = tmp; - } - - ASSERT((static_cast<char*>(end) - static_cast<char*>(start)) < 0x1000000); - ASSERT(IS_POINTER_ALIGNED(start)); - ASSERT(IS_POINTER_ALIGNED(end)); - - char** p = static_cast<char**>(start); - char** e = static_cast<char**>(end); - - size_t usedPrimaryBlocks = primaryHeap.usedBlocks; - size_t usedNumberBlocks = numberHeap.usedBlocks; - CollectorBlock** primaryBlocks = primaryHeap.blocks; - CollectorBlock** numberBlocks = numberHeap.blocks; - - const size_t lastCellOffset = sizeof(CollectorCell) * (CELLS_PER_BLOCK - 1); - - while (p != e) { - char* x = *p++; - if (IS_HALF_CELL_ALIGNED(x) && x) { - uintptr_t xAsBits = reinterpret_cast<uintptr_t>(x); - xAsBits &= CELL_ALIGN_MASK; - uintptr_t offset = xAsBits & BLOCK_OFFSET_MASK; - CollectorBlock* blockAddr = reinterpret_cast<CollectorBlock*>(xAsBits - offset); - // Mark the the number heap, we can mark these Cells directly to avoid the virtual call cost - for (size_t block = 0; block < usedNumberBlocks; block++) { - if ((numberBlocks[block] == blockAddr) & (offset <= lastCellOffset)) { - Heap::markCell(reinterpret_cast<JSCell*>(xAsBits)); - goto endMarkLoop; - } - } - - // Mark the primary heap - for (size_t block = 0; block < usedPrimaryBlocks; block++) { - if ((primaryBlocks[block] == blockAddr) & (offset <= lastCellOffset)) { - if (reinterpret_cast<CollectorCell*>(xAsBits)->u.freeCell.zeroIfFree != 0) { - JSCell* imp = reinterpret_cast<JSCell*>(xAsBits); - if (!imp->marked()) - imp->mark(); - } - break; - } - } - endMarkLoop: - ; - } - } -} - -void NEVER_INLINE Heap::markCurrentThreadConservativelyInternal() -{ - void* dummy; - void* stackPointer = &dummy; - void* stackBase = currentThreadStackBase(); - markConservatively(stackPointer, stackBase); -} - -void Heap::markCurrentThreadConservatively() -{ - // setjmp forces volatile registers onto the stack - jmp_buf registers; -#if COMPILER(MSVC) -#pragma warning(push) -#pragma warning(disable: 4611) -#endif - setjmp(registers); -#if COMPILER(MSVC) -#pragma warning(pop) -#endif - - markCurrentThreadConservativelyInternal(); -} - -#if ENABLE(JSC_MULTIPLE_THREADS) - -static inline void suspendThread(const PlatformThread& platformThread) -{ -#if PLATFORM(DARWIN) - thread_suspend(platformThread); -#elif PLATFORM(WIN_OS) - SuspendThread(platformThread.handle); -#else -#error Need a way to suspend threads on this platform -#endif -} - -static inline void resumeThread(const PlatformThread& platformThread) -{ -#if PLATFORM(DARWIN) - thread_resume(platformThread); -#elif PLATFORM(WIN_OS) - ResumeThread(platformThread.handle); -#else -#error Need a way to resume threads on this platform -#endif -} - -typedef unsigned long usword_t; // word size, assumed to be either 32 or 64 bit - -#if PLATFORM(DARWIN) - -#if PLATFORM(X86) -typedef i386_thread_state_t PlatformThreadRegisters; -#elif PLATFORM(X86_64) -typedef x86_thread_state64_t PlatformThreadRegisters; -#elif PLATFORM(PPC) -typedef ppc_thread_state_t PlatformThreadRegisters; -#elif PLATFORM(PPC64) -typedef ppc_thread_state64_t PlatformThreadRegisters; -#elif PLATFORM(ARM) -typedef arm_thread_state_t PlatformThreadRegisters; -#else -#error Unknown Architecture -#endif - -#elif PLATFORM(WIN_OS)&& PLATFORM(X86) -typedef CONTEXT PlatformThreadRegisters; -#else -#error Need a thread register struct for this platform -#endif - -size_t getPlatformThreadRegisters(const PlatformThread& platformThread, PlatformThreadRegisters& regs) -{ -#if PLATFORM(DARWIN) - -#if PLATFORM(X86) - unsigned user_count = sizeof(regs)/sizeof(int); - thread_state_flavor_t flavor = i386_THREAD_STATE; -#elif PLATFORM(X86_64) - unsigned user_count = x86_THREAD_STATE64_COUNT; - thread_state_flavor_t flavor = x86_THREAD_STATE64; -#elif PLATFORM(PPC) - unsigned user_count = PPC_THREAD_STATE_COUNT; - thread_state_flavor_t flavor = PPC_THREAD_STATE; -#elif PLATFORM(PPC64) - unsigned user_count = PPC_THREAD_STATE64_COUNT; - thread_state_flavor_t flavor = PPC_THREAD_STATE64; -#elif PLATFORM(ARM) - unsigned user_count = ARM_THREAD_STATE_COUNT; - thread_state_flavor_t flavor = ARM_THREAD_STATE; -#else -#error Unknown Architecture -#endif - - kern_return_t result = thread_get_state(platformThread, flavor, (thread_state_t)®s, &user_count); - if (result != KERN_SUCCESS) { - WTFReportFatalError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, - "JavaScript garbage collection failed because thread_get_state returned an error (%d). This is probably the result of running inside Rosetta, which is not supported.", result); - CRASH(); - } - return user_count * sizeof(usword_t); -// end PLATFORM(DARWIN) - -#elif PLATFORM(WIN_OS) && PLATFORM(X86) - regs.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS; - GetThreadContext(platformThread.handle, ®s); - return sizeof(CONTEXT); -#else -#error Need a way to get thread registers on this platform -#endif -} - -static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs) -{ -#if PLATFORM(DARWIN) - -#if __DARWIN_UNIX03 - -#if PLATFORM(X86) - return reinterpret_cast<void*>(regs.__esp); -#elif PLATFORM(X86_64) - return reinterpret_cast<void*>(regs.__rsp); -#elif PLATFORM(PPC) || PLATFORM(PPC64) - return reinterpret_cast<void*>(regs.__r1); -#elif PLATFORM(ARM) - return reinterpret_cast<void*>(regs.__sp); -#else -#error Unknown Architecture -#endif - -#else // !__DARWIN_UNIX03 - -#if PLATFORM(X86) - return reinterpret_cast<void*>(regs.esp); -#elif PLATFORM(X86_64) - return reinterpret_cast<void*>(regs.rsp); -#elif (PLATFORM(PPC) || PLATFORM(PPC64)) - return reinterpret_cast<void*>(regs.r1); -#else -#error Unknown Architecture -#endif - -#endif // __DARWIN_UNIX03 - -// end PLATFORM(DARWIN) -#elif PLATFORM(X86) && PLATFORM(WIN_OS) - return reinterpret_cast<void*>((uintptr_t) regs.Esp); -#else -#error Need a way to get the stack pointer for another thread on this platform -#endif -} - -void Heap::markOtherThreadConservatively(Thread* thread) -{ - suspendThread(thread->platformThread); - - PlatformThreadRegisters regs; - size_t regSize = getPlatformThreadRegisters(thread->platformThread, regs); - - // mark the thread's registers - markConservatively(static_cast<void*>(®s), static_cast<void*>(reinterpret_cast<char*>(®s) + regSize)); - - void* stackPointer = otherThreadStackPointer(regs); - markConservatively(stackPointer, thread->stackBase); - - resumeThread(thread->platformThread); -} - -#endif - -void Heap::markStackObjectsConservatively() -{ - markCurrentThreadConservatively(); - -#if ENABLE(JSC_MULTIPLE_THREADS) - - if (m_currentThreadRegistrar) { - - MutexLocker lock(m_registeredThreadsMutex); - -#ifndef NDEBUG - // Forbid malloc during the mark phase. Marking a thread suspends it, so - // a malloc inside mark() would risk a deadlock with a thread that had been - // suspended while holding the malloc lock. - fastMallocForbid(); -#endif - // It is safe to access the registeredThreads list, because we earlier asserted that locks are being held, - // and since this is a shared heap, they are real locks. - for (Thread* thread = m_registeredThreads; thread; thread = thread->next) { - if (!pthread_equal(thread->posixThread, pthread_self())) - markOtherThreadConservatively(thread); - } -#ifndef NDEBUG - fastMallocAllow(); -#endif - } -#endif -} - -void Heap::setGCProtectNeedsLocking() -{ - // Most clients do not need to call this, with the notable exception of WebCore. - // Clients that use shared heap have JSLock protection, while others are supposed - // to do explicit locking. WebCore violates this contract in Database code, - // which calls gcUnprotect from a secondary thread. - if (!m_protectedValuesMutex) - m_protectedValuesMutex.set(new Mutex); -} - -void Heap::protect(JSValue* k) -{ - ASSERT(k); - ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance); - - if (JSImmediate::isImmediate(k)) - return; - - if (m_protectedValuesMutex) - m_protectedValuesMutex->lock(); - - m_protectedValues.add(k->asCell()); - - if (m_protectedValuesMutex) - m_protectedValuesMutex->unlock(); -} - -void Heap::unprotect(JSValue* k) -{ - ASSERT(k); - ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance); - - if (JSImmediate::isImmediate(k)) - return; - - if (m_protectedValuesMutex) - m_protectedValuesMutex->lock(); - - m_protectedValues.remove(k->asCell()); - - if (m_protectedValuesMutex) - m_protectedValuesMutex->unlock(); -} - -Heap* Heap::heap(JSValue* v) -{ - if (JSImmediate::isImmediate(v)) - return 0; - return Heap::cellBlock(v->asCell())->heap; -} - -void Heap::markProtectedObjects() -{ - if (m_protectedValuesMutex) - m_protectedValuesMutex->lock(); - - ProtectCountSet::iterator end = m_protectedValues.end(); - for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) { - JSCell* val = it->first; - if (!val->marked()) - val->mark(); - } - - if (m_protectedValuesMutex) - m_protectedValuesMutex->unlock(); -} - -template <HeapType heapType> size_t Heap::sweep() -{ - typedef typename HeapConstants<heapType>::Block Block; - typedef typename HeapConstants<heapType>::Cell Cell; - - // SWEEP: delete everything with a zero refcount (garbage) and unmark everything else - CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap; - - size_t emptyBlocks = 0; - size_t numLiveObjects = heap.numLiveObjects; - - for (size_t block = 0; block < heap.usedBlocks; block++) { - Block* curBlock = reinterpret_cast<Block*>(heap.blocks[block]); - - size_t usedCells = curBlock->usedCells; - Cell* freeList = curBlock->freeList; - - if (usedCells == HeapConstants<heapType>::cellsPerBlock) { - // special case with a block where all cells are used -- testing indicates this happens often - for (size_t i = 0; i < HeapConstants<heapType>::cellsPerBlock; i++) { - if (!curBlock->marked.get(i >> HeapConstants<heapType>::bitmapShift)) { - Cell* cell = curBlock->cells + i; - - if (heapType != NumberHeap) { - JSCell* imp = reinterpret_cast<JSCell*>(cell); - // special case for allocated but uninitialized object - // (We don't need this check earlier because nothing prior this point - // assumes the object has a valid vptr.) - if (cell->u.freeCell.zeroIfFree == 0) - continue; - - imp->~JSCell(); - } - - --usedCells; - --numLiveObjects; - - // put cell on the free list - cell->u.freeCell.zeroIfFree = 0; - cell->u.freeCell.next = freeList - (cell + 1); - freeList = cell; - } - } - } else { - size_t minimumCellsToProcess = usedCells; - for (size_t i = 0; (i < minimumCellsToProcess) & (i < HeapConstants<heapType>::cellsPerBlock); i++) { - Cell* cell = curBlock->cells + i; - if (cell->u.freeCell.zeroIfFree == 0) { - ++minimumCellsToProcess; - } else { - if (!curBlock->marked.get(i >> HeapConstants<heapType>::bitmapShift)) { - if (heapType != NumberHeap) { - JSCell* imp = reinterpret_cast<JSCell*>(cell); - imp->~JSCell(); - } - --usedCells; - --numLiveObjects; - - // put cell on the free list - cell->u.freeCell.zeroIfFree = 0; - cell->u.freeCell.next = freeList - (cell + 1); - freeList = cell; - } - } - } - } - - curBlock->usedCells = static_cast<uint32_t>(usedCells); - curBlock->freeList = freeList; - curBlock->marked.clearAll(); - - if (usedCells == 0) { - emptyBlocks++; - if (emptyBlocks > SPARE_EMPTY_BLOCKS) { -#if !DEBUG_COLLECTOR - freeBlock(reinterpret_cast<CollectorBlock*>(curBlock)); -#endif - // swap with the last block so we compact as we go - heap.blocks[block] = heap.blocks[heap.usedBlocks - 1]; - heap.usedBlocks--; - block--; // Don't move forward a step in this case - - if (heap.numBlocks > MIN_ARRAY_SIZE && heap.usedBlocks < heap.numBlocks / LOW_WATER_FACTOR) { - heap.numBlocks = heap.numBlocks / GROWTH_FACTOR; - heap.blocks = static_cast<CollectorBlock**>(fastRealloc(heap.blocks, heap.numBlocks * sizeof(CollectorBlock*))); - } - } - } - } - - if (heap.numLiveObjects != numLiveObjects) - heap.firstBlockWithPossibleSpace = 0; - - heap.numLiveObjects = numLiveObjects; - heap.numLiveObjectsAtLastCollect = numLiveObjects; - heap.extraCost = 0; - return numLiveObjects; -} - -bool Heap::collect() -{ -#ifndef NDEBUG - if (m_globalData->isSharedInstance) { - ASSERT(JSLock::lockCount() > 0); - ASSERT(JSLock::currentThreadIsHoldingLock()); - } -#endif - - ASSERT((primaryHeap.operationInProgress == NoOperation) | (numberHeap.operationInProgress == NoOperation)); - if ((primaryHeap.operationInProgress != NoOperation) | (numberHeap.operationInProgress != NoOperation)) - abort(); - - JAVASCRIPTCORE_GC_BEGIN(); - primaryHeap.operationInProgress = Collection; - numberHeap.operationInProgress = Collection; - - // MARK: first mark all referenced objects recursively starting out from the set of root objects - - markStackObjectsConservatively(); - markProtectedObjects(); - if (m_markListSet && m_markListSet->size()) - ArgList::markLists(*m_markListSet); - if (m_globalData->exception && !m_globalData->exception->marked()) - m_globalData->exception->mark(); - m_globalData->machine->registerFile().markCallFrames(this); - m_globalData->smallStrings.mark(); - - JSGlobalObject* globalObject = m_globalData->head; - if (globalObject) { - do { - globalObject->markCrossHeapDependentObjects(); - globalObject = globalObject->next(); - } while (globalObject != m_globalData->head); - } - - JAVASCRIPTCORE_GC_MARKED(); - - size_t originalLiveObjects = primaryHeap.numLiveObjects + numberHeap.numLiveObjects; - size_t numLiveObjects = sweep<PrimaryHeap>(); - numLiveObjects += sweep<NumberHeap>(); - - primaryHeap.operationInProgress = NoOperation; - numberHeap.operationInProgress = NoOperation; - JAVASCRIPTCORE_GC_END(originalLiveObjects, numLiveObjects); - - return numLiveObjects < originalLiveObjects; -} - -size_t Heap::size() -{ - return primaryHeap.numLiveObjects + numberHeap.numLiveObjects; -} - -size_t Heap::globalObjectCount() -{ - size_t count = 0; - if (JSGlobalObject* head = m_globalData->head) { - JSGlobalObject* o = head; - do { - ++count; - o = o->next(); - } while (o != head); - } - return count; -} - -size_t Heap::protectedGlobalObjectCount() -{ - if (m_protectedValuesMutex) - m_protectedValuesMutex->lock(); - - size_t count = 0; - if (JSGlobalObject* head = m_globalData->head) { - JSGlobalObject* o = head; - do { - if (m_protectedValues.contains(o)) - ++count; - o = o->next(); - } while (o != head); - } - - if (m_protectedValuesMutex) - m_protectedValuesMutex->unlock(); - - return count; -} - -size_t Heap::protectedObjectCount() -{ - if (m_protectedValuesMutex) - m_protectedValuesMutex->lock(); - - size_t result = m_protectedValues.size(); - - if (m_protectedValuesMutex) - m_protectedValuesMutex->unlock(); - - return result; -} - -static const char* typeName(JSCell* val) -{ - if (val->isString()) - return "string"; - if (val->isNumber()) - return "number"; - if (val->isGetterSetter()) - return "gettersetter"; - ASSERT(val->isObject()); - const ClassInfo* info = static_cast<JSObject*>(val)->classInfo(); - return info ? info->className : "Object"; -} - -HashCountedSet<const char*>* Heap::protectedObjectTypeCounts() -{ - HashCountedSet<const char*>* counts = new HashCountedSet<const char*>; - - if (m_protectedValuesMutex) - m_protectedValuesMutex->lock(); - - ProtectCountSet::iterator end = m_protectedValues.end(); - for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) - counts->add(typeName(it->first)); - - if (m_protectedValuesMutex) - m_protectedValuesMutex->unlock(); - - return counts; -} - -bool Heap::isBusy() -{ - return (primaryHeap.operationInProgress != NoOperation) | (numberHeap.operationInProgress != NoOperation); -} - -Heap::iterator Heap::primaryHeapBegin() -{ - return iterator(primaryHeap.blocks, primaryHeap.blocks + primaryHeap.usedBlocks); -} - -Heap::iterator Heap::primaryHeapEnd() -{ - return iterator(primaryHeap.blocks + primaryHeap.usedBlocks, primaryHeap.blocks + primaryHeap.usedBlocks); -} - -} // namespace JSC diff --git a/JavaScriptCore/kjs/collector.h b/JavaScriptCore/kjs/collector.h deleted file mode 100644 index 4233b06..0000000 --- a/JavaScriptCore/kjs/collector.h +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. 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 - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef KJSCOLLECTOR_H_ -#define KJSCOLLECTOR_H_ - -#include "JSImmediate.h" -#include <string.h> -#include <wtf/HashCountedSet.h> -#include <wtf/HashSet.h> -#include <wtf/Noncopyable.h> -#include <wtf/OwnPtr.h> -#include <wtf/Threading.h> - -// This is supremely lame that we require pthreads to build on windows. -#if ENABLE(JSC_MULTIPLE_THREADS) -#include <pthread.h> -#endif - -#define ASSERT_CLASS_FITS_IN_CELL(class) COMPILE_ASSERT(sizeof(class) <= CELL_SIZE, class_fits_in_cell) - -namespace JSC { - - class ArgList; - class CollectorBlock; - class JSCell; - class JSGlobalData; - - enum OperationInProgress { NoOperation, Allocation, Collection }; - enum HeapType { PrimaryHeap, NumberHeap }; - - template <HeapType> class CollectorHeapIterator; - - struct CollectorHeap { - CollectorBlock** blocks; - size_t numBlocks; - size_t usedBlocks; - size_t firstBlockWithPossibleSpace; - - size_t numLiveObjects; - size_t numLiveObjectsAtLastCollect; - size_t extraCost; - - OperationInProgress operationInProgress; - }; - - class Heap : Noncopyable { - public: - class Thread; - typedef CollectorHeapIterator<PrimaryHeap> iterator; - - void destroy(); - -#ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE - // We can inline these functions because everything is compiled as - // one file, so the heapAllocate template definitions are available. - // However, allocateNumber is used via jsNumberCell outside JavaScriptCore. - // Thus allocateNumber needs to provide a non-inline version too. - void* inlineAllocateNumber(size_t s) { return heapAllocate<NumberHeap>(s); } - void* inlineAllocate(size_t s) { return heapAllocate<PrimaryHeap>(s); } -#endif - void* allocateNumber(size_t); - void* allocate(size_t); - - bool collect(); - bool isBusy(); // true if an allocation or collection is in progress - - static const size_t minExtraCostSize = 256; - - void reportExtraMemoryCost(size_t cost); - - size_t size(); - - void setGCProtectNeedsLocking(); - void protect(JSValue*); - void unprotect(JSValue*); - - static Heap* heap(JSValue*); // 0 for immediate values - - size_t globalObjectCount(); - size_t protectedObjectCount(); - size_t protectedGlobalObjectCount(); - HashCountedSet<const char*>* protectedObjectTypeCounts(); - - void registerThread(); // Only needs to be called by clients that can use the same heap from multiple threads. - - static bool isCellMarked(const JSCell*); - static void markCell(JSCell*); - - void markConservatively(void* start, void* end); - - HashSet<ArgList*>& markListSet() { if (!m_markListSet) m_markListSet = new HashSet<ArgList*>; return *m_markListSet; } - - JSGlobalData* globalData() const { return m_globalData; } - static bool isNumber(JSCell*); - - // Iterators for the object heap. - iterator primaryHeapBegin(); - iterator primaryHeapEnd(); - - private: - template <HeapType heapType> void* heapAllocate(size_t); - template <HeapType heapType> size_t sweep(); - static CollectorBlock* cellBlock(const JSCell*); - static size_t cellOffset(const JSCell*); - - friend class JSGlobalData; - Heap(JSGlobalData*); - ~Heap(); - - void recordExtraCost(size_t); - void markProtectedObjects(); - void markCurrentThreadConservatively(); - void markCurrentThreadConservativelyInternal(); - void markOtherThreadConservatively(Thread*); - void markStackObjectsConservatively(); - - typedef HashCountedSet<JSCell*> ProtectCountSet; - - CollectorHeap primaryHeap; - CollectorHeap numberHeap; - - OwnPtr<Mutex> m_protectedValuesMutex; // Only non-null if the client explicitly requested it via setGCPrtotectNeedsLocking(). - ProtectCountSet m_protectedValues; - - HashSet<ArgList*>* m_markListSet; - -#if ENABLE(JSC_MULTIPLE_THREADS) - static void unregisterThread(void*); - void unregisterThread(); - - Mutex m_registeredThreadsMutex; - Thread* m_registeredThreads; - pthread_key_t m_currentThreadRegistrar; -#endif - - JSGlobalData* m_globalData; - }; - - // tunable parameters - template<size_t bytesPerWord> struct CellSize; - - // cell size needs to be a power of two for certain optimizations in collector.cpp - template<> struct CellSize<sizeof(uint32_t)> { static const size_t m_value = 32; }; // 32-bit - template<> struct CellSize<sizeof(uint64_t)> { static const size_t m_value = 64; }; // 64-bit - const size_t BLOCK_SIZE = 16 * 4096; // 64k - - // derived constants - const size_t BLOCK_OFFSET_MASK = BLOCK_SIZE - 1; - const size_t BLOCK_MASK = ~BLOCK_OFFSET_MASK; - const size_t MINIMUM_CELL_SIZE = CellSize<sizeof(void*)>::m_value; - const size_t CELL_ARRAY_LENGTH = (MINIMUM_CELL_SIZE / sizeof(double)) + (MINIMUM_CELL_SIZE % sizeof(double) != 0 ? sizeof(double) : 0); - const size_t CELL_SIZE = CELL_ARRAY_LENGTH * sizeof(double); - const size_t SMALL_CELL_SIZE = CELL_SIZE / 2; - const size_t CELL_MASK = CELL_SIZE - 1; - const size_t CELL_ALIGN_MASK = ~CELL_MASK; - const size_t CELLS_PER_BLOCK = (BLOCK_SIZE * 8 - sizeof(uint32_t) * 8 - sizeof(void *) * 8 - 2 * (7 + 3 * 8)) / (CELL_SIZE * 8 + 2); - const size_t SMALL_CELLS_PER_BLOCK = 2 * CELLS_PER_BLOCK; - const size_t BITMAP_SIZE = (CELLS_PER_BLOCK + 7) / 8; - const size_t BITMAP_WORDS = (BITMAP_SIZE + 3) / sizeof(uint32_t); - - struct CollectorBitmap { - uint32_t bits[BITMAP_WORDS]; - bool get(size_t n) const { return !!(bits[n >> 5] & (1 << (n & 0x1F))); } - void set(size_t n) { bits[n >> 5] |= (1 << (n & 0x1F)); } - void clear(size_t n) { bits[n >> 5] &= ~(1 << (n & 0x1F)); } - void clearAll() { memset(bits, 0, sizeof(bits)); } - }; - - struct CollectorCell { - union { - double memory[CELL_ARRAY_LENGTH]; - struct { - void* zeroIfFree; - ptrdiff_t next; - } freeCell; - } u; - }; - - struct SmallCollectorCell { - union { - double memory[CELL_ARRAY_LENGTH / 2]; - struct { - void* zeroIfFree; - ptrdiff_t next; - } freeCell; - } u; - }; - - class CollectorBlock { - public: - CollectorCell cells[CELLS_PER_BLOCK]; - uint32_t usedCells; - CollectorCell* freeList; - CollectorBitmap marked; - Heap* heap; - HeapType type; - }; - - class SmallCellCollectorBlock { - public: - SmallCollectorCell cells[SMALL_CELLS_PER_BLOCK]; - uint32_t usedCells; - SmallCollectorCell* freeList; - CollectorBitmap marked; - Heap* heap; - HeapType type; - }; - - template <HeapType heapType> struct HeapConstants; - - template <> struct HeapConstants<PrimaryHeap> { - static const size_t cellSize = CELL_SIZE; - static const size_t cellsPerBlock = CELLS_PER_BLOCK; - static const size_t bitmapShift = 0; - typedef CollectorCell Cell; - typedef CollectorBlock Block; - }; - - template <> struct HeapConstants<NumberHeap> { - static const size_t cellSize = SMALL_CELL_SIZE; - static const size_t cellsPerBlock = SMALL_CELLS_PER_BLOCK; - static const size_t bitmapShift = 1; - typedef SmallCollectorCell Cell; - typedef SmallCellCollectorBlock Block; - }; - - inline CollectorBlock* Heap::cellBlock(const JSCell* cell) - { - return reinterpret_cast<CollectorBlock*>(reinterpret_cast<uintptr_t>(cell) & BLOCK_MASK); - } - - inline bool Heap::isNumber(JSCell* cell) - { - return Heap::cellBlock(cell)->type == NumberHeap; - } - - inline size_t Heap::cellOffset(const JSCell* cell) - { - return (reinterpret_cast<uintptr_t>(cell) & BLOCK_OFFSET_MASK) / CELL_SIZE; - } - - inline bool Heap::isCellMarked(const JSCell* cell) - { - return cellBlock(cell)->marked.get(cellOffset(cell)); - } - - inline void Heap::markCell(JSCell* cell) - { - cellBlock(cell)->marked.set(cellOffset(cell)); - } - - inline void Heap::reportExtraMemoryCost(size_t cost) - { - if (cost > minExtraCostSize) - recordExtraCost(cost / (CELL_SIZE * 2)); - } - -} // namespace JSC - -#endif /* KJSCOLLECTOR_H_ */ diff --git a/JavaScriptCore/kjs/completion.h b/JavaScriptCore/kjs/completion.h deleted file mode 100644 index 56d13ed..0000000 --- a/JavaScriptCore/kjs/completion.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) - * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2007 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#ifndef KJS_COMPLETION_H -#define KJS_COMPLETION_H - -#include "JSValue.h" - -namespace JSC { - - enum ComplType { Normal, Break, Continue, ReturnValue, Throw, Interrupted }; - - /* - * Completion objects are used to convey the return status and value - * from functions. - */ - class Completion { - public: - Completion(ComplType type = Normal, JSValue* value = noValue()) - : m_type(type) - , m_value(value) - { - } - - ComplType complType() const { return m_type; } - JSValue* value() const { return m_value; } - void setValue(JSValue* v) { m_value = v; } - bool isValueCompletion() const { return !!m_value; } - - private: - ComplType m_type; - JSValue* m_value; - }; - -} // namespace JSC - -#endif // KJS_COMPLETION_H diff --git a/JavaScriptCore/kjs/config.h b/JavaScriptCore/kjs/config.h deleted file mode 100644 index 80a3798..0000000 --- a/JavaScriptCore/kjs/config.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H -#include "autotoolsconfig.h" -#endif - -#include <wtf/Platform.h> - -#if PLATFORM(ANDROID) - -#define ANDROID_MOBILE // change can be merged back to WebKit.org for MOBILE -//#define ANDROID_INSTRUMENT -#endif - -#if PLATFORM(WIN_OS) - -// If we don't define these, they get defined in windef.h. -// We want to use std::min and std::max -#define max max -#define min min - -#if !COMPILER(MSVC7) -// We need to define this before the first #include of stdlib.h or it won't contain rand_s. -#ifndef _CRT_RAND_S -#define _CRT_RAND_S -#endif -#endif - -#endif - -#if PLATFORM(FREEBSD) || PLATFORM(OPENBSD) -#define HAVE_PTHREAD_NP_H 1 -#endif - -/* FIXME: if all platforms have these, do they really need #defines? */ -#define HAVE_STDINT_H 1 -#define HAVE_STRING_H 1 - -#define WTF_CHANGES 1 - -#ifdef __cplusplus -#undef new -#undef delete -#include <wtf/FastMalloc.h> -#endif - -// this breaks compilation of <QFontDatabase>, at least, so turn it off for now -// Also generates errors on wx on Windows, because these functions -// are used from wx headers. -#if !PLATFORM(QT) && !PLATFORM(WX) -#include <wtf/DisallowCType.h> -#endif diff --git a/JavaScriptCore/kjs/create_hash_table b/JavaScriptCore/kjs/create_hash_table deleted file mode 100755 index 829a024..0000000 --- a/JavaScriptCore/kjs/create_hash_table +++ /dev/null @@ -1,242 +0,0 @@ -#! /usr/bin/perl -w -# -# Static Hashtable Generator -# -# (c) 2000-2002 by Harri Porten <porten@kde.org> and -# David Faure <faure@kde.org> -# Modified (c) 2004 by Nikolas Zimmermann <wildfox@kde.org> -# Copyright (C) 2007 Apple Inc. All rights reserved. -# -# Part of the KJS library. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -# - -use strict; - -my $file = $ARGV[0]; -shift; -my $includelookup = 0; - -# Use -i as second argument to make it include "lookup.h" -$includelookup = 1 if (defined($ARGV[0]) && $ARGV[0] eq "-i"); - -# Use -n as second argument to make it use the third argument as namespace parameter ie. -n KDOM -my $useNameSpace = $ARGV[1] if (defined($ARGV[0]) && $ARGV[0] eq "-n"); - -print STDERR "Creating hashtable for $file\n"; -open(IN, $file) or die "No such file $file"; - -my @keys = (); -my @attrs = (); -my @values = (); -my @hashes = (); - -my $inside = 0; -my $name; -my $size; -my $banner = 0; -sub calcSize(); -sub output(); -sub jsc_ucfirst($); -sub hashValue($); - -while (<IN>) { - chomp; - s/^\s+//; - next if /^\#|^$/; # Comment or blank line. Do nothing. - if (/^\@begin/ && !$inside) { - if (/^\@begin\s*([:_\w]+)\s*\d*\s*$/) { - $inside = 1; - $name = $1; - } else { - print STDERR "WARNING: \@begin without table name, skipping $_\n"; - } - } elsif (/^\@end\s*$/ && $inside) { - calcSize(); - output(); - - @keys = (); - @attrs = (); - @values = (); - @hashes = (); - - $inside = 0; - } elsif (/^(\S+)\s*(\S+)\s*([\w\|]*)\s*(\w*)\s*$/ && $inside) { - my $key = $1; - my $val = $2; - my $att = $3; - my $param = $4; - - push(@keys, $key); - push(@attrs, length($att) > 0 ? $att : "0"); - - if ($att =~ m/Function/) { - push(@values, { "type" => "Function", "function" => $val, "params" => (length($param) ? $param : "") }); - #printf STDERR "WARNING: Number of arguments missing for $key/$val\n" if (length($param) == 0); - } elsif (length($att)) { - my $get = $val; - my $put = !($att =~ m/ReadOnly/) ? "set" . jsc_ucfirst($val) : "0"; - push(@values, { "type" => "Property", "get" => $get, "put" => $put }); - } else { - push(@values, { "type" => "Lexer", "value" => $val }); - } - push(@hashes, hashValue($key)); - } elsif ($inside) { - die "invalid data {" . $_ . "}"; - } -} - -die "missing closing \@end" if ($inside); - -sub jsc_ucfirst($) -{ - my ($value) = @_; - - if ($value =~ /js/) { - $value =~ s/js/JS/; - return $value; - } - - return ucfirst($value); -} - - -sub ceilingToPowerOf2 -{ - my ($size) = @_; - - my $powerOf2 = 1; - while ($size > $powerOf2) { - $powerOf2 <<= 1; - } - - return $powerOf2; -} - -sub calcSize() -{ -tableSizeLoop: - for ($size = ceilingToPowerOf2(scalar @keys); ; $size += $size) { - my @table = (); - foreach my $key (@keys) { - my $h = hashValue($key) % $size; - next tableSizeLoop if $table[$h]; - $table[$h] = 1; - } - last; - } -} - -sub leftShift($$) { - my ($value, $distance) = @_; - return (($value << $distance) & 0xFFFFFFFF); -} - -# Paul Hsieh's SuperFastHash -# http://www.azillionmonkeys.com/qed/hash.html -# Ported from UString.. -sub hashValue($) { - my @chars = split(/ */, $_[0]); - - # This hash is designed to work on 16-bit chunks at a time. But since the normal case - # (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they - # were 16-bit chunks, which should give matching results - - my $EXP2_32 = 4294967296; - - my $hash = 0x9e3779b9; - my $l = scalar @chars; #I wish this was in Ruby --- Maks - my $rem = $l & 1; - $l = $l >> 1; - - my $s = 0; - - # Main loop - for (; $l > 0; $l--) { - $hash += ord($chars[$s]); - my $tmp = leftShift(ord($chars[$s+1]), 11) ^ $hash; - $hash = (leftShift($hash, 16)% $EXP2_32) ^ $tmp; - $s += 2; - $hash += $hash >> 11; - $hash %= $EXP2_32; - } - - # Handle end case - if ($rem !=0) { - $hash += ord($chars[$s]); - $hash ^= (leftShift($hash, 11)% $EXP2_32); - $hash += $hash >> 17; - } - - # Force "avalanching" of final 127 bits - $hash ^= leftShift($hash, 3); - $hash += ($hash >> 5); - $hash = ($hash% $EXP2_32); - $hash ^= (leftShift($hash, 2)% $EXP2_32); - $hash += ($hash >> 15); - $hash = $hash% $EXP2_32; - $hash ^= (leftShift($hash, 10)% $EXP2_32); - - # this avoids ever returning a hash code of 0, since that is used to - # signal "hash not computed yet", using a value that is likely to be - # effectively the same as 0 when the low bits are masked - $hash = 0x80000000 if ($hash == 0); - - return $hash; -} - -sub output() { - if (!$banner) { - $banner = 1; - print "// Automatically generated from $file using $0. DO NOT EDIT!\n"; - } - - my $nameEntries = "${name}Values"; - $nameEntries =~ s/:/_/g; - - print "\n#include \"lookup.h\"\n" if ($includelookup); - if ($useNameSpace) { - print "\nnamespace ${useNameSpace} {\n"; - print "\nusing namespace JSC;\n"; - } else { - print "\nnamespace JSC {\n"; - } - my $count = scalar @keys + 1; - print "\nstatic const struct HashTableValue ${nameEntries}\[$count\] = {\n"; - my $i = 0; - foreach my $key (@keys) { - my $firstValue = ""; - my $secondValue = ""; - - if ($values[$i]{"type"} eq "Function") { - $firstValue = $values[$i]{"function"}; - $secondValue = $values[$i]{"params"}; - } elsif ($values[$i]{"type"} eq "Property") { - $firstValue = $values[$i]{"get"}; - $secondValue = $values[$i]{"put"}; - } elsif ($values[$i]{"type"} eq "Lexer") { - $firstValue = $values[$i]{"value"}; - $secondValue = "0"; - } - print " { \"$key\", $attrs[$i], (intptr_t)$firstValue, (intptr_t)$secondValue },\n"; - $i++; - } - print " { 0, 0, 0, 0 }\n"; - print "};\n\n"; - print "extern const struct HashTable $name = "; - print "\{ ", $size - 1, ", $nameEntries, 0 \};\n\n"; - print "} // namespace\n"; -} diff --git a/JavaScriptCore/kjs/dtoa.cpp b/JavaScriptCore/kjs/dtoa.cpp deleted file mode 100644 index 2dc2cff..0000000 --- a/JavaScriptCore/kjs/dtoa.cpp +++ /dev/null @@ -1,2438 +0,0 @@ -/**************************************************************** - * - * The author of this software is David M. Gay. - * - * Copyright (c) 1991, 2000, 2001 by Lucent Technologies. - * Copyright (C) 2002, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY - * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - * - ***************************************************************/ - -/* Please send bug reports to - David M. Gay - Bell Laboratories, Room 2C-463 - 600 Mountain Avenue - Murray Hill, NJ 07974-0636 - U.S.A. - dmg@bell-labs.com - */ - -/* On a machine with IEEE extended-precision registers, it is - * necessary to specify double-precision (53-bit) rounding precision - * before invoking strtod or dtoa. If the machine uses (the equivalent - * of) Intel 80x87 arithmetic, the call - * _control87(PC_53, MCW_PC); - * does this with many compilers. Whether this or another call is - * appropriate depends on the compiler; for this to work, it may be - * necessary to #include "float.h" or another system-dependent header - * file. - */ - -/* strtod for IEEE-arithmetic machines. - * - * This strtod returns a nearest machine number to the input decimal - * string (or sets errno to ERANGE). With IEEE arithmetic, ties are - * broken by the IEEE round-even rule. Otherwise ties are broken by - * biased rounding (add half and chop). - * - * Inspired loosely by William D. Clinger's paper "How to Read Floating - * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. - * - * Modifications: - * - * 1. We only require IEEE. - * 2. We get by with floating-point arithmetic in a case that - * Clinger missed -- when we're computing d * 10^n - * for a small integer d and the integer n is not too - * much larger than 22 (the maximum integer k for which - * we can represent 10^k exactly), we may be able to - * compute (d*10^k) * 10^(e-k) with just one roundoff. - * 3. Rather than a bit-at-a-time adjustment of the binary - * result in the hard case, we use floating-point - * arithmetic to determine the adjustment to within - * one bit; only in really hard cases do we need to - * compute a second residual. - * 4. Because of 3., we don't need a large table of powers of 10 - * for ten-to-e (just some small tables, e.g. of 10^k - * for 0 <= k <= 22). - */ - -/* - * #define IEEE_8087 for IEEE-arithmetic machines where the least - * significant byte has the lowest address. - * #define IEEE_MC68k for IEEE-arithmetic machines where the most - * significant byte has the lowest address. - * #define No_leftright to omit left-right logic in fast floating-point - * computation of dtoa. - * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 - * and Honor_FLT_ROUNDS is not #defined. - * #define Inaccurate_Divide for IEEE-format with correctly rounded - * products but inaccurate quotients, e.g., for Intel i860. - * #define USE_LONG_LONG on machines that have a "long long" - * integer type (of >= 64 bits), and performance testing shows that - * it is faster than 32-bit fallback (which is often not the case - * on 32-bit machines). On such machines, you can #define Just_16 - * to store 16 bits per 32-bit int32_t when doing high-precision integer - * arithmetic. Whether this speeds things up or slows things down - * depends on the machine and the number being converted. - * #define Bad_float_h if your system lacks a float.h or if it does not - * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, - * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. - * #define INFNAN_CHECK on IEEE systems to cause strtod to check for - * Infinity and NaN (case insensitively). On some systems (e.g., - * some HP systems), it may be necessary to #define NAN_WORD0 - * appropriately -- to the most significant word of a quiet NaN. - * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.) - * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined, - * strtod also accepts (case insensitively) strings of the form - * NaN(x), where x is a string of hexadecimal digits and spaces; - * if there is only one string of hexadecimal digits, it is taken - * for the 52 fraction bits of the resulting NaN; if there are two - * or more strings of hex digits, the first is for the high 20 bits, - * the second and subsequent for the low 32 bits, with intervening - * white space ignored; but if this results in none of the 52 - * fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0 - * and NAN_WORD1 are used instead. - * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that - * avoids underflows on inputs whose result does not underflow. - * If you #define NO_IEEE_Scale on a machine that uses IEEE-format - * floating-point numbers and flushes underflows to zero rather - * than implementing gradual underflow, then you must also #define - * Sudden_Underflow. - * #define YES_ALIAS to permit aliasing certain double values with - * arrays of ULongs. This leads to slightly better code with - * some compilers and was always used prior to 19990916, but it - * is not strictly legal and can cause trouble with aggressively - * optimizing compilers (e.g., gcc 2.95.1 under -O2). - * #define SET_INEXACT if IEEE arithmetic is being used and extra - * computation should be done to set the inexact flag when the - * result is inexact and avoid setting inexact when the result - * is exact. In this case, dtoa.c must be compiled in - * an environment, perhaps provided by #include "dtoa.c" in a - * suitable wrapper, that defines two functions, - * int get_inexact(void); - * void clear_inexact(void); - * such that get_inexact() returns a nonzero value if the - * inexact bit is already set, and clear_inexact() sets the - * inexact bit to 0. When SET_INEXACT is #defined, strtod - * also does extra computations to set the underflow and overflow - * flags when appropriate (i.e., when the result is tiny and - * inexact or when it is a numeric value rounded to +-infinity). - * #define NO_ERRNO if strtod should not assign errno = ERANGE when - * the result overflows to +-Infinity or underflows to 0. - */ - -#include "config.h" -#include "dtoa.h" - -#include <errno.h> -#include <float.h> -#include <math.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <wtf/AlwaysInline.h> -#include <wtf/Assertions.h> -#include <wtf/FastMalloc.h> -#include <wtf/Threading.h> - -#if COMPILER(MSVC) -#pragma warning(disable: 4244) -#pragma warning(disable: 4245) -#pragma warning(disable: 4554) -#endif - -// ANDROID : || PLATFORM(MIDDLE_ENDIAN) added in #if statement below -// for dtoa, MIDDLE_ENDIAN needs to be same as BIG_ENDIAN according to the following site -// http://lists.debian.org/debian-arm/2003/11/msg00008.html -#if PLATFORM(BIG_ENDIAN) || PLATFORM(MIDDLE_ENDIAN) -#define IEEE_MC68k -#elif PLATFORM(MIDDLE_ENDIAN) -#define IEEE_ARM -#else -#define IEEE_8087 -#endif - -#define INFNAN_CHECK - -#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(IEEE_ARM) != 1 -Exactly one of IEEE_8087, IEEE_ARM or IEEE_MC68k should be defined. -#endif - -namespace JSC { - -#if ENABLE(JSC_MULTIPLE_THREADS) -Mutex* s_dtoaP5Mutex; -#endif - -typedef union { double d; uint32_t L[2]; } U; - -#ifdef YES_ALIAS -#define dval(x) x -#ifdef IEEE_8087 -#define word0(x) ((uint32_t*)&x)[1] -#define word1(x) ((uint32_t*)&x)[0] -#else -#define word0(x) ((uint32_t*)&x)[0] -#define word1(x) ((uint32_t*)&x)[1] -#endif -#else -#ifdef IEEE_8087 -#define word0(x) ((U*)&x)->L[1] -#define word1(x) ((U*)&x)->L[0] -#else -#define word0(x) ((U*)&x)->L[0] -#define word1(x) ((U*)&x)->L[1] -#endif -#define dval(x) ((U*)&x)->d -#endif - -/* The following definition of Storeinc is appropriate for MIPS processors. - * An alternative that might be better on some machines is - * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) - */ -#if defined(IEEE_8087) || defined(IEEE_ARM) -#define Storeinc(a,b,c) (((unsigned short*)a)[1] = (unsigned short)b, ((unsigned short*)a)[0] = (unsigned short)c, a++) -#else -#define Storeinc(a,b,c) (((unsigned short*)a)[0] = (unsigned short)b, ((unsigned short*)a)[1] = (unsigned short)c, a++) -#endif - -#define Exp_shift 20 -#define Exp_shift1 20 -#define Exp_msk1 0x100000 -#define Exp_msk11 0x100000 -#define Exp_mask 0x7ff00000 -#define P 53 -#define Bias 1023 -#define Emin (-1022) -#define Exp_1 0x3ff00000 -#define Exp_11 0x3ff00000 -#define Ebits 11 -#define Frac_mask 0xfffff -#define Frac_mask1 0xfffff -#define Ten_pmax 22 -#define Bletch 0x10 -#define Bndry_mask 0xfffff -#define Bndry_mask1 0xfffff -#define LSB 1 -#define Sign_bit 0x80000000 -#define Log2P 1 -#define Tiny0 0 -#define Tiny1 1 -#define Quick_max 14 -#define Int_max 14 - -#if !defined(NO_IEEE_Scale) -#undef Avoid_Underflow -#define Avoid_Underflow -#endif - -#if !defined(Flt_Rounds) -#if defined(FLT_ROUNDS) -#define Flt_Rounds FLT_ROUNDS -#else -#define Flt_Rounds 1 -#endif -#endif /*Flt_Rounds*/ - - -#define rounded_product(a,b) a *= b -#define rounded_quotient(a,b) a /= b - -#define Big0 (Frac_mask1 | Exp_msk1 * (DBL_MAX_EXP + Bias - 1)) -#define Big1 0xffffffff - -#ifndef Pack_32 -#define Pack_32 -#endif - -#if PLATFORM(PPC64) || PLATFORM(X86_64) -// 64-bit emulation provided by the compiler is likely to be slower than dtoa own code on 32-bit hardware. -#define USE_LONG_LONG -#endif - -#ifndef USE_LONG_LONG -#ifdef Just_16 -#undef Pack_32 -/* When Pack_32 is not defined, we store 16 bits per 32-bit int32_t. - * This makes some inner loops simpler and sometimes saves work - * during multiplications, but it often seems to make things slightly - * slower. Hence the default is now to store 32 bits per int32_t. - */ -#endif -#endif - -#define Kmax 15 - -struct Bigint { - struct Bigint* next; - int k, maxwds, sign, wds; - uint32_t x[1]; -}; - -static Bigint* Balloc(int k) -{ - int x = 1 << k; - Bigint* rv = (Bigint*)fastMalloc(sizeof(Bigint) + (x - 1)*sizeof(uint32_t)); - rv->k = k; - rv->maxwds = x; - rv->next = 0; - rv->sign = rv->wds = 0; - - return rv; -} - -static void Bfree(Bigint* v) -{ - fastFree(v); -} - -#define Bcopy(x, y) memcpy((char*)&x->sign, (char*)&y->sign, y->wds * sizeof(int32_t) + 2 * sizeof(int)) - -static Bigint* multadd(Bigint* b, int m, int a) /* multiply by m and add a */ -{ -#ifdef USE_LONG_LONG - unsigned long long carry; -#else - uint32_t carry; -#endif - - int wds = b->wds; - uint32_t* x = b->x; - int i = 0; - carry = a; - do { -#ifdef USE_LONG_LONG - unsigned long long y = *x * (unsigned long long)m + carry; - carry = y >> 32; - *x++ = (uint32_t)y & 0xffffffffUL; -#else -#ifdef Pack_32 - uint32_t xi = *x; - uint32_t y = (xi & 0xffff) * m + carry; - uint32_t z = (xi >> 16) * m + (y >> 16); - carry = z >> 16; - *x++ = (z << 16) + (y & 0xffff); -#else - uint32_t y = *x * m + carry; - carry = y >> 16; - *x++ = y & 0xffff; -#endif -#endif - } while (++i < wds); - - if (carry) { - if (wds >= b->maxwds) { - Bigint* b1 = Balloc(b->k + 1); - Bcopy(b1, b); - Bfree(b); - b = b1; - } - b->x[wds++] = (uint32_t)carry; - b->wds = wds; - } - return b; -} - -static Bigint* s2b(const char* s, int nd0, int nd, uint32_t y9) -{ - int k; - int32_t y; - int32_t x = (nd + 8) / 9; - - for (k = 0, y = 1; x > y; y <<= 1, k++) { } -#ifdef Pack_32 - Bigint* b = Balloc(k); - b->x[0] = y9; - b->wds = 1; -#else - Bigint* b = Balloc(k + 1); - b->x[0] = y9 & 0xffff; - b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; -#endif - - int i = 9; - if (9 < nd0) { - s += 9; - do { - b = multadd(b, 10, *s++ - '0'); - } while (++i < nd0); - s++; - } else - s += 10; - for (; i < nd; i++) - b = multadd(b, 10, *s++ - '0'); - return b; -} - -static int hi0bits(uint32_t x) -{ - int k = 0; - - if (!(x & 0xffff0000)) { - k = 16; - x <<= 16; - } - if (!(x & 0xff000000)) { - k += 8; - x <<= 8; - } - if (!(x & 0xf0000000)) { - k += 4; - x <<= 4; - } - if (!(x & 0xc0000000)) { - k += 2; - x <<= 2; - } - if (!(x & 0x80000000)) { - k++; - if (!(x & 0x40000000)) - return 32; - } - return k; -} - -static int lo0bits (uint32_t* y) -{ - int k; - uint32_t x = *y; - - if (x & 7) { - if (x & 1) - return 0; - if (x & 2) { - *y = x >> 1; - return 1; - } - *y = x >> 2; - return 2; - } - k = 0; - if (!(x & 0xffff)) { - k = 16; - x >>= 16; - } - if (!(x & 0xff)) { - k += 8; - x >>= 8; - } - if (!(x & 0xf)) { - k += 4; - x >>= 4; - } - if (!(x & 0x3)) { - k += 2; - x >>= 2; - } - if (!(x & 1)) { - k++; - x >>= 1; - if (!x & 1) - return 32; - } - *y = x; - return k; -} - -static Bigint* i2b(int i) -{ - Bigint* b; - - b = Balloc(1); - b->x[0] = i; - b->wds = 1; - return b; -} - -static Bigint* mult(Bigint* a, Bigint* b) -{ - Bigint* c; - int k, wa, wb, wc; - uint32_t *x, *xa, *xae, *xb, *xbe, *xc, *xc0; - uint32_t y; -#ifdef USE_LONG_LONG - unsigned long long carry, z; -#else - uint32_t carry, z; -#endif - - if (a->wds < b->wds) { - c = a; - a = b; - b = c; - } - k = a->k; - wa = a->wds; - wb = b->wds; - wc = wa + wb; - if (wc > a->maxwds) - k++; - c = Balloc(k); - for (x = c->x, xa = x + wc; x < xa; x++) - *x = 0; - xa = a->x; - xae = xa + wa; - xb = b->x; - xbe = xb + wb; - xc0 = c->x; -#ifdef USE_LONG_LONG - for (; xb < xbe; xc0++) { - if ((y = *xb++)) { - x = xa; - xc = xc0; - carry = 0; - do { - z = *x++ * (unsigned long long)y + *xc + carry; - carry = z >> 32; - *xc++ = (uint32_t)z & 0xffffffffUL; - } while (x < xae); - *xc = (uint32_t)carry; - } - } -#else -#ifdef Pack_32 - for (; xb < xbe; xb++, xc0++) { - if ((y = *xb & 0xffff)) { - x = xa; - xc = xc0; - carry = 0; - do { - z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; - carry = z >> 16; - uint32_t z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; - carry = z2 >> 16; - Storeinc(xc, z2, z); - } while (x < xae); - *xc = carry; - } - if ((y = *xb >> 16)) { - x = xa; - xc = xc0; - carry = 0; - uint32_t z2 = *xc; - do { - z = (*x & 0xffff) * y + (*xc >> 16) + carry; - carry = z >> 16; - Storeinc(xc, z, z2); - z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; - carry = z2 >> 16; - } while (x < xae); - *xc = z2; - } - } -#else - for(; xb < xbe; xc0++) { - if ((y = *xb++)) { - x = xa; - xc = xc0; - carry = 0; - do { - z = *x++ * y + *xc + carry; - carry = z >> 16; - *xc++ = z & 0xffff; - } while (x < xae); - *xc = carry; - } - } -#endif -#endif - for (xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) { } - c->wds = wc; - return c; -} - -static Bigint* p5s; -static int p5s_count; - -static Bigint* pow5mult(Bigint* b, int k) -{ - static int p05[3] = { 5, 25, 125 }; - - if (int i = k & 3) - b = multadd(b, p05[i - 1], 0); - - if (!(k >>= 2)) - return b; - -#if ENABLE(JSC_MULTIPLE_THREADS) - s_dtoaP5Mutex->lock(); -#endif - Bigint* p5 = p5s; - if (!p5) { - /* first time */ - p5 = p5s = i2b(625); - p5s_count = 1; - } - int p5s_count_local = p5s_count; -#if ENABLE(JSC_MULTIPLE_THREADS) - s_dtoaP5Mutex->unlock(); -#endif - int p5s_used = 0; - - for (;;) { - if (k & 1) { - Bigint* b1 = mult(b, p5); - Bfree(b); - b = b1; - } - if (!(k >>= 1)) - break; - - if (++p5s_used == p5s_count_local) { -#if ENABLE(JSC_MULTIPLE_THREADS) - s_dtoaP5Mutex->lock(); -#endif - if (p5s_used == p5s_count) { - ASSERT(!p5->next); - p5->next = mult(p5, p5); - ++p5s_count; - } - - p5s_count_local = p5s_count; -#if ENABLE(JSC_MULTIPLE_THREADS) - s_dtoaP5Mutex->unlock(); -#endif - } - p5 = p5->next; - } - - return b; -} - -static Bigint* lshift(Bigint* b, int k) -{ - Bigint* result = b; - -#ifdef Pack_32 - int n = k >> 5; -#else - int n = k >> 4; -#endif - - int k1 = b->k; - int n1 = n + b->wds + 1; - for (int i = b->maxwds; n1 > i; i <<= 1) - k1++; - if (b->k < k1) - result = Balloc(k1); - - const uint32_t* srcStart = b->x; - uint32_t* dstStart = result->x; - const uint32_t* src = srcStart + b->wds - 1; - uint32_t* dst = dstStart + n1 - 1; -#ifdef Pack_32 - if (k &= 0x1f) { - uint32_t hiSubword = 0; - int s = 32 - k; - for (; src >= srcStart; --src) { - *dst-- = hiSubword | *src >> s; - hiSubword = *src << k; - } - *dst = hiSubword; - ASSERT(dst == dstStart + n); - result->wds = b->wds + n + (result->x[n1 - 1] != 0); - } -#else - if (k &= 0xf) { - uint32_t hiSubword = 0; - int s = 16 - k; - for (; src >= srcStart; --src) { - *dst-- = hiSubword | *src >> s; - hiSubword = (*src << k) & 0xffff; - } - *dst = hiSubword; - ASSERT(dst == dstStart + n); - result->wds = b->wds + n + (result->x[n1 - 1] != 0); - } - #endif - else { - do { - *--dst = *src--; - } while (src >= srcStart); - result->wds = b->wds + n; - } - for (dst = dstStart + n; dst != dstStart; ) - *--dst = 0; - - if (result != b) - Bfree(b); - return result; -} - -static int cmp(Bigint* a, Bigint* b) -{ - uint32_t *xa, *xa0, *xb, *xb0; - int i, j; - - i = a->wds; - j = b->wds; - ASSERT(i <= 1 || a->x[i - 1]); - ASSERT(j <= 1 || b->x[j - 1]); - if (i -= j) - return i; - xa0 = a->x; - xa = xa0 + j; - xb0 = b->x; - xb = xb0 + j; - for (;;) { - if (*--xa != *--xb) - return *xa < *xb ? -1 : 1; - if (xa <= xa0) - break; - } - return 0; -} - -static Bigint* diff(Bigint* a, Bigint* b) -{ - Bigint* c; - int i, wa, wb; - uint32_t *xa, *xae, *xb, *xbe, *xc; - - i = cmp(a,b); - if (!i) { - c = Balloc(0); - c->wds = 1; - c->x[0] = 0; - return c; - } - if (i < 0) { - c = a; - a = b; - b = c; - i = 1; - } else - i = 0; - c = Balloc(a->k); - c->sign = i; - wa = a->wds; - xa = a->x; - xae = xa + wa; - wb = b->wds; - xb = b->x; - xbe = xb + wb; - xc = c->x; -#ifdef USE_LONG_LONG - unsigned long long borrow = 0; - do { - unsigned long long y = (unsigned long long)*xa++ - *xb++ - borrow; - borrow = y >> 32 & (uint32_t)1; - *xc++ = (uint32_t)y & 0xffffffffUL; - } while (xb < xbe); - while (xa < xae) { - unsigned long long y = *xa++ - borrow; - borrow = y >> 32 & (uint32_t)1; - *xc++ = (uint32_t)y & 0xffffffffUL; - } -#else - uint32_t borrow = 0; -#ifdef Pack_32 - do { - uint32_t y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - uint32_t z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(xc, z, y); - } while (xb < xbe); - while (xa < xae) { - uint32_t y = (*xa & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - uint32_t z = (*xa++ >> 16) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(xc, z, y); - } -#else - do { - uint32_t y = *xa++ - *xb++ - borrow; - borrow = (y & 0x10000) >> 16; - *xc++ = y & 0xffff; - } while (xb < xbe); - while (xa < xae) { - uint32_t y = *xa++ - borrow; - borrow = (y & 0x10000) >> 16; - *xc++ = y & 0xffff; - } -#endif -#endif - while (!*--xc) - wa--; - c->wds = wa; - return c; -} - -static double ulp(double x) -{ - register int32_t L; - double a; - - L = (word0(x) & Exp_mask) - (P - 1) * Exp_msk1; -#ifndef Avoid_Underflow -#ifndef Sudden_Underflow - if (L > 0) { -#endif -#endif - word0(a) = L; - word1(a) = 0; -#ifndef Avoid_Underflow -#ifndef Sudden_Underflow - } else { - L = -L >> Exp_shift; - if (L < Exp_shift) { - word0(a) = 0x80000 >> L; - word1(a) = 0; - } else { - word0(a) = 0; - L -= Exp_shift; - word1(a) = L >= 31 ? 1 : 1 << 31 - L; - } - } -#endif -#endif - return dval(a); -} - -static double b2d(Bigint* a, int* e) -{ - uint32_t* xa; - uint32_t* xa0; - uint32_t w; - uint32_t y; - uint32_t z; - int k; - double d; - -#define d0 word0(d) -#define d1 word1(d) - - xa0 = a->x; - xa = xa0 + a->wds; - y = *--xa; - ASSERT(y); - k = hi0bits(y); - *e = 32 - k; -#ifdef Pack_32 - if (k < Ebits) { - d0 = Exp_1 | y >> Ebits - k; - w = xa > xa0 ? *--xa : 0; - d1 = y << (32 - Ebits) + k | w >> Ebits - k; - goto ret_d; - } - z = xa > xa0 ? *--xa : 0; - if (k -= Ebits) { - d0 = Exp_1 | y << k | z >> 32 - k; - y = xa > xa0 ? *--xa : 0; - d1 = z << k | y >> 32 - k; - } else { - d0 = Exp_1 | y; - d1 = z; - } -#else - if (k < Ebits + 16) { - z = xa > xa0 ? *--xa : 0; - d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; - w = xa > xa0 ? *--xa : 0; - y = xa > xa0 ? *--xa : 0; - d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; - goto ret_d; - } - z = xa > xa0 ? *--xa : 0; - w = xa > xa0 ? *--xa : 0; - k -= Ebits + 16; - d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; - y = xa > xa0 ? *--xa : 0; - d1 = w << k + 16 | y << k; -#endif -ret_d: -#undef d0 -#undef d1 - return dval(d); -} - -static Bigint* d2b(double d, int* e, int* bits) -{ - Bigint* b; - int de, k; - uint32_t *x, y, z; -#ifndef Sudden_Underflow - int i; -#endif -#define d0 word0(d) -#define d1 word1(d) - -#ifdef Pack_32 - b = Balloc(1); -#else - b = Balloc(2); -#endif - x = b->x; - - z = d0 & Frac_mask; - d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ -#ifdef Sudden_Underflow - de = (int)(d0 >> Exp_shift); -#else - if ((de = (int)(d0 >> Exp_shift))) - z |= Exp_msk1; -#endif -#ifdef Pack_32 - if ((y = d1)) { - if ((k = lo0bits(&y))) { - x[0] = y | z << 32 - k; - z >>= k; - } else - x[0] = y; -#ifndef Sudden_Underflow - i = -#endif - b->wds = (x[1] = z) ? 2 : 1; - } else { - k = lo0bits(&z); - x[0] = z; -#ifndef Sudden_Underflow - i = -#endif - b->wds = 1; - k += 32; - } -#else - if ((y = d1)) { - if ((k = lo0bits(&y))) { - if (k >= 16) { - x[0] = y | z << 32 - k & 0xffff; - x[1] = z >> k - 16 & 0xffff; - x[2] = z >> k; - i = 2; - } else { - x[0] = y & 0xffff; - x[1] = y >> 16 | z << 16 - k & 0xffff; - x[2] = z >> k & 0xffff; - x[3] = z >> k + 16; - i = 3; - } - } else { - x[0] = y & 0xffff; - x[1] = y >> 16; - x[2] = z & 0xffff; - x[3] = z >> 16; - i = 3; - } - } else { - k = lo0bits(&z); - if (k >= 16) { - x[0] = z; - i = 0; - } else { - x[0] = z & 0xffff; - x[1] = z >> 16; - i = 1; - } - k += 32; - } while (!x[i]) - --i; - b->wds = i + 1; -#endif -#ifndef Sudden_Underflow - if (de) { -#endif - *e = de - Bias - (P - 1) + k; - *bits = P - k; -#ifndef Sudden_Underflow - } else { - *e = de - Bias - (P - 1) + 1 + k; -#ifdef Pack_32 - *bits = (32 * i) - hi0bits(x[i - 1]); -#else - *bits = (i + 2) * 16 - hi0bits(x[i]); -#endif - } -#endif - return b; -} -#undef d0 -#undef d1 - -static double ratio(Bigint* a, Bigint* b) -{ - double da, db; - int k, ka, kb; - - dval(da) = b2d(a, &ka); - dval(db) = b2d(b, &kb); -#ifdef Pack_32 - k = ka - kb + 32 * (a->wds - b->wds); -#else - k = ka - kb + 16 * (a->wds - b->wds); -#endif - if (k > 0) - word0(da) += k * Exp_msk1; - else { - k = -k; - word0(db) += k * Exp_msk1; - } - return dval(da) / dval(db); -} - -static const double tens[] = { - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, - 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, - 1e20, 1e21, 1e22 -}; - -static const double bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; -static const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, -#ifdef Avoid_Underflow - 9007199254740992. * 9007199254740992.e-256 - /* = 2^106 * 1e-53 */ -#else - 1e-256 -#endif -}; - -/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */ -/* flag unnecessarily. It leads to a song and dance at the end of strtod. */ -#define Scale_Bit 0x10 -#define n_bigtens 5 - -#if defined(INFNAN_CHECK) - -#ifndef NAN_WORD0 -#define NAN_WORD0 0x7ff80000 -#endif - -#ifndef NAN_WORD1 -#define NAN_WORD1 0 -#endif - -static int match(const char** sp, const char* t) -{ - int c, d; - const char* s = *sp; - - while ((d = *t++)) { - if ((c = *++s) >= 'A' && c <= 'Z') - c += 'a' - 'A'; - if (c != d) - return 0; - } - *sp = s + 1; - return 1; -} - -#ifndef No_Hex_NaN -static void hexnan(double* rvp, const char** sp) -{ - uint32_t c, x[2]; - const char* s; - int havedig, udx0, xshift; - - x[0] = x[1] = 0; - havedig = xshift = 0; - udx0 = 1; - s = *sp; - while ((c = *(const unsigned char*)++s)) { - if (c >= '0' && c <= '9') - c -= '0'; - else if (c >= 'a' && c <= 'f') - c += 10 - 'a'; - else if (c >= 'A' && c <= 'F') - c += 10 - 'A'; - else if (c <= ' ') { - if (udx0 && havedig) { - udx0 = 0; - xshift = 1; - } - continue; - } else if (/*(*/ c == ')' && havedig) { - *sp = s + 1; - break; - } else - return; /* invalid form: don't change *sp */ - havedig = 1; - if (xshift) { - xshift = 0; - x[0] = x[1]; - x[1] = 0; - } - if (udx0) - x[0] = (x[0] << 4) | (x[1] >> 28); - x[1] = (x[1] << 4) | c; - } - if ((x[0] &= 0xfffff) || x[1]) { - word0(*rvp) = Exp_mask | x[0]; - word1(*rvp) = x[1]; - } -} -#endif /*No_Hex_NaN*/ -#endif /* INFNAN_CHECK */ - -double strtod(const char* s00, char** se) -{ -#ifdef Avoid_Underflow - int scale; -#endif - int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, - e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; - const char *s, *s0, *s1; - double aadj, aadj1, adj, rv, rv0; - int32_t L; - uint32_t y, z; - Bigint *bb = NULL, *bb1 = NULL, *bd = NULL, *bd0 = NULL, *bs = NULL, *delta = NULL; -#ifdef SET_INEXACT - int inexact, oldinexact; -#endif - - sign = nz0 = nz = 0; - dval(rv) = 0.; - for (s = s00; ; s++) - switch (*s) { - case '-': - sign = 1; - /* no break */ - case '+': - if (*++s) - goto break2; - /* no break */ - case 0: - goto ret0; - case '\t': - case '\n': - case '\v': - case '\f': - case '\r': - case ' ': - continue; - default: - goto break2; - } -break2: - if (*s == '0') { - nz0 = 1; - while (*++s == '0') { } - if (!*s) - goto ret; - } - s0 = s; - y = z = 0; - for (nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) - if (nd < 9) - y = (10 * y) + c - '0'; - else if (nd < 16) - z = (10 * z) + c - '0'; - nd0 = nd; - if (c == '.') { - c = *++s; - if (!nd) { - for (; c == '0'; c = *++s) - nz++; - if (c > '0' && c <= '9') { - s0 = s; - nf += nz; - nz = 0; - goto have_dig; - } - goto dig_done; - } - for (; c >= '0' && c <= '9'; c = *++s) { -have_dig: - nz++; - if (c -= '0') { - nf += nz; - for (i = 1; i < nz; i++) - if (nd++ < 9) - y *= 10; - else if (nd <= DBL_DIG + 1) - z *= 10; - if (nd++ < 9) - y = (10 * y) + c; - else if (nd <= DBL_DIG + 1) - z = (10 * z) + c; - nz = 0; - } - } - } -dig_done: - e = 0; - if (c == 'e' || c == 'E') { - if (!nd && !nz && !nz0) { - goto ret0; - } - s00 = s; - esign = 0; - switch (c = *++s) { - case '-': - esign = 1; - case '+': - c = *++s; - } - if (c >= '0' && c <= '9') { - while (c == '0') - c = *++s; - if (c > '0' && c <= '9') { - L = c - '0'; - s1 = s; - while ((c = *++s) >= '0' && c <= '9') - L = (10 * L) + c - '0'; - if (s - s1 > 8 || L > 19999) - /* Avoid confusion from exponents - * so large that e might overflow. - */ - e = 19999; /* safe for 16 bit ints */ - else - e = (int)L; - if (esign) - e = -e; - } else - e = 0; - } else - s = s00; - } - if (!nd) { - if (!nz && !nz0) { -#ifdef INFNAN_CHECK - /* Check for Nan and Infinity */ - switch(c) { - case 'i': - case 'I': - if (match(&s,"nf")) { - --s; - if (!match(&s,"inity")) - ++s; - word0(rv) = 0x7ff00000; - word1(rv) = 0; - goto ret; - } - break; - case 'n': - case 'N': - if (match(&s, "an")) { - word0(rv) = NAN_WORD0; - word1(rv) = NAN_WORD1; -#ifndef No_Hex_NaN - if (*s == '(') /*)*/ - hexnan(&rv, &s); -#endif - goto ret; - } - } -#endif /* INFNAN_CHECK */ -ret0: - s = s00; - sign = 0; - } - goto ret; - } - e1 = e -= nf; - - /* Now we have nd0 digits, starting at s0, followed by a - * decimal point, followed by nd-nd0 digits. The number we're - * after is the integer represented by those digits times - * 10**e */ - - if (!nd0) - nd0 = nd; - k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; - dval(rv) = y; - if (k > 9) { -#ifdef SET_INEXACT - if (k > DBL_DIG) - oldinexact = get_inexact(); -#endif - dval(rv) = tens[k - 9] * dval(rv) + z; - } - bd0 = 0; - if (nd <= DBL_DIG && Flt_Rounds == 1) { - if (!e) - goto ret; - if (e > 0) { - if (e <= Ten_pmax) { - /* rv = */ rounded_product(dval(rv), tens[e]); - goto ret; - } - i = DBL_DIG - nd; - if (e <= Ten_pmax + i) { - /* A fancier test would sometimes let us do - * this for larger i values. - */ - e -= i; - dval(rv) *= tens[i]; - /* rv = */ rounded_product(dval(rv), tens[e]); - goto ret; - } - } -#ifndef Inaccurate_Divide - else if (e >= -Ten_pmax) { - /* rv = */ rounded_quotient(dval(rv), tens[-e]); - goto ret; - } -#endif - } - e1 += nd - k; - -#ifdef SET_INEXACT - inexact = 1; - if (k <= DBL_DIG) - oldinexact = get_inexact(); -#endif -#ifdef Avoid_Underflow - scale = 0; -#endif - - /* Get starting approximation = rv * 10**e1 */ - - if (e1 > 0) { - if ((i = e1 & 15)) - dval(rv) *= tens[i]; - if (e1 &= ~15) { - if (e1 > DBL_MAX_10_EXP) { -ovfl: -#ifndef NO_ERRNO - errno = ERANGE; -#endif - /* Can't trust HUGE_VAL */ - word0(rv) = Exp_mask; - word1(rv) = 0; -#ifdef SET_INEXACT - /* set overflow bit */ - dval(rv0) = 1e300; - dval(rv0) *= dval(rv0); -#endif - if (bd0) - goto retfree; - goto ret; - } - e1 >>= 4; - for (j = 0; e1 > 1; j++, e1 >>= 1) - if (e1 & 1) - dval(rv) *= bigtens[j]; - /* The last multiplication could overflow. */ - word0(rv) -= P * Exp_msk1; - dval(rv) *= bigtens[j]; - if ((z = word0(rv) & Exp_mask) > Exp_msk1 * (DBL_MAX_EXP + Bias - P)) - goto ovfl; - if (z > Exp_msk1 * (DBL_MAX_EXP + Bias - 1 - P)) { - /* set to largest number */ - /* (Can't trust DBL_MAX) */ - word0(rv) = Big0; - word1(rv) = Big1; - } else - word0(rv) += P * Exp_msk1; - } - } else if (e1 < 0) { - e1 = -e1; - if ((i = e1 & 15)) - dval(rv) /= tens[i]; - if (e1 >>= 4) { - if (e1 >= 1 << n_bigtens) - goto undfl; -#ifdef Avoid_Underflow - if (e1 & Scale_Bit) - scale = 2 * P; - for (j = 0; e1 > 0; j++, e1 >>= 1) - if (e1 & 1) - dval(rv) *= tinytens[j]; - if (scale && (j = (2 * P) + 1 - ((word0(rv) & Exp_mask) >> Exp_shift)) > 0) { - /* scaled rv is denormal; zap j low bits */ - if (j >= 32) { - word1(rv) = 0; - if (j >= 53) - word0(rv) = (P + 2) * Exp_msk1; - else - word0(rv) &= 0xffffffff << j - 32; - } else - word1(rv) &= 0xffffffff << j; - } -#else - for (j = 0; e1 > 1; j++, e1 >>= 1) - if (e1 & 1) - dval(rv) *= tinytens[j]; - /* The last multiplication could underflow. */ - dval(rv0) = dval(rv); - dval(rv) *= tinytens[j]; - if (!dval(rv)) { - dval(rv) = 2. * dval(rv0); - dval(rv) *= tinytens[j]; -#endif - if (!dval(rv)) { -undfl: - dval(rv) = 0.; -#ifndef NO_ERRNO - errno = ERANGE; -#endif - if (bd0) - goto retfree; - goto ret; - } -#ifndef Avoid_Underflow - word0(rv) = Tiny0; - word1(rv) = Tiny1; - /* The refinement below will clean - * this approximation up. - */ - } -#endif - } - } - - /* Now the hard part -- adjusting rv to the correct value.*/ - - /* Put digits into bd: true value = bd * 10^e */ - - bd0 = s2b(s0, nd0, nd, y); - - for (;;) { - bd = Balloc(bd0->k); - Bcopy(bd, bd0); - bb = d2b(dval(rv), &bbe, &bbbits); /* rv = bb * 2^bbe */ - bs = i2b(1); - - if (e >= 0) { - bb2 = bb5 = 0; - bd2 = bd5 = e; - } else { - bb2 = bb5 = -e; - bd2 = bd5 = 0; - } - if (bbe >= 0) - bb2 += bbe; - else - bd2 -= bbe; - bs2 = bb2; -#ifdef Avoid_Underflow - j = bbe - scale; - i = j + bbbits - 1; /* logb(rv) */ - if (i < Emin) /* denormal */ - j += P - Emin; - else - j = P + 1 - bbbits; -#else /*Avoid_Underflow*/ -#ifdef Sudden_Underflow - j = P + 1 - bbbits; -#else /*Sudden_Underflow*/ - j = bbe; - i = j + bbbits - 1; /* logb(rv) */ - if (i < Emin) /* denormal */ - j += P - Emin; - else - j = P + 1 - bbbits; -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow*/ - bb2 += j; - bd2 += j; -#ifdef Avoid_Underflow - bd2 += scale; -#endif - i = bb2 < bd2 ? bb2 : bd2; - if (i > bs2) - i = bs2; - if (i > 0) { - bb2 -= i; - bd2 -= i; - bs2 -= i; - } - if (bb5 > 0) { - bs = pow5mult(bs, bb5); - bb1 = mult(bs, bb); - Bfree(bb); - bb = bb1; - } - if (bb2 > 0) - bb = lshift(bb, bb2); - if (bd5 > 0) - bd = pow5mult(bd, bd5); - if (bd2 > 0) - bd = lshift(bd, bd2); - if (bs2 > 0) - bs = lshift(bs, bs2); - delta = diff(bb, bd); - dsign = delta->sign; - delta->sign = 0; - i = cmp(delta, bs); - - if (i < 0) { - /* Error is less than half an ulp -- check for - * special case of mantissa a power of two. - */ - if (dsign || word1(rv) || word0(rv) & Bndry_mask -#ifdef Avoid_Underflow - || (word0(rv) & Exp_mask) <= (2 * P + 1) * Exp_msk1 -#else - || (word0(rv) & Exp_mask) <= Exp_msk1 -#endif - ) { -#ifdef SET_INEXACT - if (!delta->x[0] && delta->wds <= 1) - inexact = 0; -#endif - break; - } - if (!delta->x[0] && delta->wds <= 1) { - /* exact result */ -#ifdef SET_INEXACT - inexact = 0; -#endif - break; - } - delta = lshift(delta,Log2P); - if (cmp(delta, bs) > 0) - goto drop_down; - break; - } - if (i == 0) { - /* exactly half-way between */ - if (dsign) { - if ((word0(rv) & Bndry_mask1) == Bndry_mask1 - && word1(rv) == ( -#ifdef Avoid_Underflow - (scale && (y = word0(rv) & Exp_mask) <= 2 * P * Exp_msk1) - ? (0xffffffff & (0xffffffff << (2 * P + 1 - (y >> Exp_shift)))) : -#endif - 0xffffffff)) { - /*boundary case -- increment exponent*/ - word0(rv) = (word0(rv) & Exp_mask) + Exp_msk1; - word1(rv) = 0; -#ifdef Avoid_Underflow - dsign = 0; -#endif - break; - } - } else if (!(word0(rv) & Bndry_mask) && !word1(rv)) { -drop_down: - /* boundary case -- decrement exponent */ -#ifdef Sudden_Underflow /*{{*/ - L = word0(rv) & Exp_mask; -#ifdef Avoid_Underflow - if (L <= (scale ? (2 * P + 1) * Exp_msk1 : Exp_msk1)) -#else - if (L <= Exp_msk1) -#endif /*Avoid_Underflow*/ - goto undfl; - L -= Exp_msk1; -#else /*Sudden_Underflow}{*/ -#ifdef Avoid_Underflow - if (scale) { - L = word0(rv) & Exp_mask; - if (L <= (2 * P + 1) * Exp_msk1) { - if (L > (P + 2) * Exp_msk1) - /* round even ==> */ - /* accept rv */ - break; - /* rv = smallest denormal */ - goto undfl; - } - } -#endif /*Avoid_Underflow*/ - L = (word0(rv) & Exp_mask) - Exp_msk1; -#endif /*Sudden_Underflow}}*/ - word0(rv) = L | Bndry_mask1; - word1(rv) = 0xffffffff; - break; - } - if (!(word1(rv) & LSB)) - break; - if (dsign) - dval(rv) += ulp(dval(rv)); - else { - dval(rv) -= ulp(dval(rv)); -#ifndef Sudden_Underflow - if (!dval(rv)) - goto undfl; -#endif - } -#ifdef Avoid_Underflow - dsign = 1 - dsign; -#endif - break; - } - if ((aadj = ratio(delta, bs)) <= 2.) { - if (dsign) - aadj = aadj1 = 1.; - else if (word1(rv) || word0(rv) & Bndry_mask) { -#ifndef Sudden_Underflow - if (word1(rv) == Tiny1 && !word0(rv)) - goto undfl; -#endif - aadj = 1.; - aadj1 = -1.; - } else { - /* special case -- power of FLT_RADIX to be */ - /* rounded down... */ - - if (aadj < 2. / FLT_RADIX) - aadj = 1. / FLT_RADIX; - else - aadj *= 0.5; - aadj1 = -aadj; - } - } else { - aadj *= 0.5; - aadj1 = dsign ? aadj : -aadj; -#ifdef Check_FLT_ROUNDS - switch (Rounding) { - case 2: /* towards +infinity */ - aadj1 -= 0.5; - break; - case 0: /* towards 0 */ - case 3: /* towards -infinity */ - aadj1 += 0.5; - } -#else - if (Flt_Rounds == 0) - aadj1 += 0.5; -#endif /*Check_FLT_ROUNDS*/ - } - y = word0(rv) & Exp_mask; - - /* Check for overflow */ - - if (y == Exp_msk1 * (DBL_MAX_EXP + Bias - 1)) { - dval(rv0) = dval(rv); - word0(rv) -= P * Exp_msk1; - adj = aadj1 * ulp(dval(rv)); - dval(rv) += adj; - if ((word0(rv) & Exp_mask) >= Exp_msk1 * (DBL_MAX_EXP + Bias - P)) { - if (word0(rv0) == Big0 && word1(rv0) == Big1) - goto ovfl; - word0(rv) = Big0; - word1(rv) = Big1; - goto cont; - } else - word0(rv) += P * Exp_msk1; - } else { -#ifdef Avoid_Underflow - if (scale && y <= 2 * P * Exp_msk1) { - if (aadj <= 0x7fffffff) { - if ((z = (uint32_t)aadj) <= 0) - z = 1; - aadj = z; - aadj1 = dsign ? aadj : -aadj; - } - word0(aadj1) += (2 * P + 1) * Exp_msk1 - y; - } - adj = aadj1 * ulp(dval(rv)); - dval(rv) += adj; -#else -#ifdef Sudden_Underflow - if ((word0(rv) & Exp_mask) <= P * Exp_msk1) { - dval(rv0) = dval(rv); - word0(rv) += P * Exp_msk1; - adj = aadj1 * ulp(dval(rv)); - dval(rv) += adj; - if ((word0(rv) & Exp_mask) <= P * Exp_msk1) - { - if (word0(rv0) == Tiny0 && word1(rv0) == Tiny1) - goto undfl; - word0(rv) = Tiny0; - word1(rv) = Tiny1; - goto cont; - } - else - word0(rv) -= P * Exp_msk1; - } else { - adj = aadj1 * ulp(dval(rv)); - dval(rv) += adj; - } -#else /*Sudden_Underflow*/ - /* Compute adj so that the IEEE rounding rules will - * correctly round rv + adj in some half-way cases. - * If rv * ulp(rv) is denormalized (i.e., - * y <= (P - 1) * Exp_msk1), we must adjust aadj to avoid - * trouble from bits lost to denormalization; - * example: 1.2e-307 . - */ - if (y <= (P - 1) * Exp_msk1 && aadj > 1.) { - aadj1 = (double)(int)(aadj + 0.5); - if (!dsign) - aadj1 = -aadj1; - } - adj = aadj1 * ulp(dval(rv)); - dval(rv) += adj; -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow*/ - } - z = word0(rv) & Exp_mask; -#ifndef SET_INEXACT -#ifdef Avoid_Underflow - if (!scale) -#endif - if (y == z) { - /* Can we stop now? */ - L = (int32_t)aadj; - aadj -= L; - /* The tolerances below are conservative. */ - if (dsign || word1(rv) || word0(rv) & Bndry_mask) { - if (aadj < .4999999 || aadj > .5000001) - break; - } else if (aadj < .4999999 / FLT_RADIX) - break; - } -#endif -cont: - Bfree(bb); - Bfree(bd); - Bfree(bs); - Bfree(delta); - } -#ifdef SET_INEXACT - if (inexact) { - if (!oldinexact) { - word0(rv0) = Exp_1 + (70 << Exp_shift); - word1(rv0) = 0; - dval(rv0) += 1.; - } - } else if (!oldinexact) - clear_inexact(); -#endif -#ifdef Avoid_Underflow - if (scale) { - word0(rv0) = Exp_1 - 2 * P * Exp_msk1; - word1(rv0) = 0; - dval(rv) *= dval(rv0); -#ifndef NO_ERRNO - /* try to avoid the bug of testing an 8087 register value */ - if (word0(rv) == 0 && word1(rv) == 0) - errno = ERANGE; -#endif - } -#endif /* Avoid_Underflow */ -#ifdef SET_INEXACT - if (inexact && !(word0(rv) & Exp_mask)) { - /* set underflow bit */ - dval(rv0) = 1e-300; - dval(rv0) *= dval(rv0); - } -#endif -retfree: - Bfree(bb); - Bfree(bd); - Bfree(bs); - Bfree(bd0); - Bfree(delta); -ret: - if (se) - *se = (char*)s; - return sign ? -dval(rv) : dval(rv); -} - -static int quorem(Bigint* b, Bigint* S) -{ - int n; - uint32_t *bx, *bxe, q, *sx, *sxe; -#ifdef USE_LONG_LONG - unsigned long long borrow, carry, y, ys; -#else - uint32_t borrow, carry, y, ys; -#ifdef Pack_32 - uint32_t si, z, zs; -#endif -#endif - - n = S->wds; - ASSERT_WITH_MESSAGE(b->wds <= n, "oversize b in quorem"); - if (b->wds < n) - return 0; - sx = S->x; - sxe = sx + --n; - bx = b->x; - bxe = bx + n; - q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ - ASSERT_WITH_MESSAGE(q <= 9, "oversized quotient in quorem"); - if (q) { - borrow = 0; - carry = 0; - do { -#ifdef USE_LONG_LONG - ys = *sx++ * (unsigned long long)q + carry; - carry = ys >> 32; - y = *bx - (ys & 0xffffffffUL) - borrow; - borrow = y >> 32 & (uint32_t)1; - *bx++ = (uint32_t)y & 0xffffffffUL; -#else -#ifdef Pack_32 - si = *sx++; - ys = (si & 0xffff) * q + carry; - zs = (si >> 16) * q + (ys >> 16); - carry = zs >> 16; - y = (*bx & 0xffff) - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - z = (*bx >> 16) - (zs & 0xffff) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(bx, z, y); -#else - ys = *sx++ * q + carry; - carry = ys >> 16; - y = *bx - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - *bx++ = y & 0xffff; -#endif -#endif - } while (sx <= sxe); - if (!*bxe) { - bx = b->x; - while (--bxe > bx && !*bxe) - --n; - b->wds = n; - } - } - if (cmp(b, S) >= 0) { - q++; - borrow = 0; - carry = 0; - bx = b->x; - sx = S->x; - do { -#ifdef USE_LONG_LONG - ys = *sx++ + carry; - carry = ys >> 32; - y = *bx - (ys & 0xffffffffUL) - borrow; - borrow = y >> 32 & (uint32_t)1; - *bx++ = (uint32_t)y & 0xffffffffUL; -#else -#ifdef Pack_32 - si = *sx++; - ys = (si & 0xffff) + carry; - zs = (si >> 16) + (ys >> 16); - carry = zs >> 16; - y = (*bx & 0xffff) - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - z = (*bx >> 16) - (zs & 0xffff) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(bx, z, y); -#else - ys = *sx++ + carry; - carry = ys >> 16; - y = *bx - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - *bx++ = y & 0xffff; -#endif -#endif - } while (sx <= sxe); - bx = b->x; - bxe = bx + n; - if (!*bxe) { - while (--bxe > bx && !*bxe) - --n; - b->wds = n; - } - } - return q; -} - -#if !ENABLE(JSC_MULTIPLE_THREADS) -static char* dtoa_result; -#endif - -static char* rv_alloc(int i) -{ - int k; - - int j = sizeof(uint32_t); - for (k = 0; - sizeof(Bigint) - sizeof(uint32_t) - sizeof(int) + j <= (unsigned)i; - j <<= 1) - k++; - int* r = (int*)Balloc(k); - *r = k; - return -#if !ENABLE(JSC_MULTIPLE_THREADS) - dtoa_result = -#endif - (char*)(r + 1); -} - -static char* nrv_alloc(const char* s, char** rve, int n) -{ - char* rv = rv_alloc(n); - char* t = rv; - - while ((*t = *s++)) - t++; - if (rve) - *rve = t; - return rv; -} - -/* freedtoa(s) must be used to free values s returned by dtoa - * when MULTIPLE_THREADS is #defined. It should be used in all cases, - * but for consistency with earlier versions of dtoa, it is optional - * when MULTIPLE_THREADS is not defined. - */ - -void freedtoa(char* s) -{ - Bigint* b = (Bigint*)((int*)s - 1); - b->maxwds = 1 << (b->k = *(int*)b); - Bfree(b); -#if !ENABLE(JSC_MULTIPLE_THREADS) - if (s == dtoa_result) - dtoa_result = 0; -#endif -} - -/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. - * - * Inspired by "How to Print Floating-Point Numbers Accurately" by - * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101]. - * - * Modifications: - * 1. Rather than iterating, we use a simple numeric overestimate - * to determine k = floor(log10(d)). We scale relevant - * quantities using O(log2(k)) rather than O(k) multiplications. - * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't - * try to generate digits strictly left to right. Instead, we - * compute with fewer bits and propagate the carry if necessary - * when rounding the final digit up. This is often faster. - * 3. Under the assumption that input will be rounded nearest, - * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. - * That is, we allow equality in stopping tests when the - * round-nearest rule will give the same floating-point value - * as would satisfaction of the stopping test with strict - * inequality. - * 4. We remove common factors of powers of 2 from relevant - * quantities. - * 5. When converting floating-point integers less than 1e16, - * we use floating-point arithmetic rather than resorting - * to multiple-precision integers. - * 6. When asked to produce fewer than 15 digits, we first try - * to get by with floating-point arithmetic; we resort to - * multiple-precision integer arithmetic only if we cannot - * guarantee that the floating-point calculation has given - * the correctly rounded result. For k requested digits and - * "uniformly" distributed input, the probability is - * something like 10^(k-15) that we must resort to the int32_t - * calculation. - */ - -char* dtoa(double d, int ndigits, int* decpt, int* sign, char** rve) -{ - /* - Arguments ndigits, decpt, sign are similar to those - of ecvt and fcvt; trailing zeros are suppressed from - the returned string. If not null, *rve is set to point - to the end of the return value. If d is +-Infinity or NaN, - then *decpt is set to 9999. - - */ - - int bbits, b2, b5, be, dig, i, ieps, ilim = 0, ilim0, ilim1 = 0, - j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, - spec_case, try_quick; - int32_t L; -#ifndef Sudden_Underflow - int denorm; - uint32_t x; -#endif - Bigint *b, *b1, *delta, *mlo = NULL, *mhi, *S; - double d2, ds, eps; - char *s, *s0; -#ifdef SET_INEXACT - int inexact, oldinexact; -#endif - -#if !ENABLE(JSC_MULTIPLE_THREADS) - if (dtoa_result) { - freedtoa(dtoa_result); - dtoa_result = 0; - } -#endif - - if (word0(d) & Sign_bit) { - /* set sign for everything, including 0's and NaNs */ - *sign = 1; - word0(d) &= ~Sign_bit; /* clear sign bit */ - } else - *sign = 0; - - if ((word0(d) & Exp_mask) == Exp_mask) - { - /* Infinity or NaN */ - *decpt = 9999; - if (!word1(d) && !(word0(d) & 0xfffff)) - return nrv_alloc("Infinity", rve, 8); - return nrv_alloc("NaN", rve, 3); - } - if (!dval(d)) { - *decpt = 1; - return nrv_alloc("0", rve, 1); - } - -#ifdef SET_INEXACT - try_quick = oldinexact = get_inexact(); - inexact = 1; -#endif - - b = d2b(dval(d), &be, &bbits); -#ifdef Sudden_Underflow - i = (int)(word0(d) >> Exp_shift1 & (Exp_mask >> Exp_shift1)); -#else - if ((i = (int)(word0(d) >> Exp_shift1 & (Exp_mask >> Exp_shift1)))) { -#endif - dval(d2) = dval(d); - word0(d2) &= Frac_mask1; - word0(d2) |= Exp_11; - - /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 - * log10(x) = log(x) / log(10) - * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) - * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) - * - * This suggests computing an approximation k to log10(d) by - * - * k = (i - Bias)*0.301029995663981 - * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); - * - * We want k to be too large rather than too small. - * The error in the first-order Taylor series approximation - * is in our favor, so we just round up the constant enough - * to compensate for any error in the multiplication of - * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, - * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, - * adding 1e-13 to the constant term more than suffices. - * Hence we adjust the constant term to 0.1760912590558. - * (We could get a more accurate k by invoking log10, - * but this is probably not worthwhile.) - */ - - i -= Bias; -#ifndef Sudden_Underflow - denorm = 0; - } else { - /* d is denormalized */ - - i = bbits + be + (Bias + (P - 1) - 1); - x = i > 32 ? word0(d) << 64 - i | word1(d) >> i - 32 - : word1(d) << 32 - i; - dval(d2) = x; - word0(d2) -= 31 * Exp_msk1; /* adjust exponent */ - i -= (Bias + (P - 1) - 1) + 1; - denorm = 1; - } -#endif - ds = (dval(d2) - 1.5) * 0.289529654602168 + 0.1760912590558 + (i * 0.301029995663981); - k = (int)ds; - if (ds < 0. && ds != k) - k--; /* want k = floor(ds) */ - k_check = 1; - if (k >= 0 && k <= Ten_pmax) { - if (dval(d) < tens[k]) - k--; - k_check = 0; - } - j = bbits - i - 1; - if (j >= 0) { - b2 = 0; - s2 = j; - } else { - b2 = -j; - s2 = 0; - } - if (k >= 0) { - b5 = 0; - s5 = k; - s2 += k; - } else { - b2 -= k; - b5 = -k; - s5 = 0; - } - -#ifndef SET_INEXACT -#ifdef Check_FLT_ROUNDS - try_quick = Rounding == 1; -#else - try_quick = 1; -#endif -#endif /*SET_INEXACT*/ - - leftright = 1; - ilim = ilim1 = -1; - i = 18; - ndigits = 0; - s = s0 = rv_alloc(i); - - if (ilim >= 0 && ilim <= Quick_max && try_quick) { - - /* Try to get by with floating-point arithmetic. */ - - i = 0; - dval(d2) = dval(d); - k0 = k; - ilim0 = ilim; - ieps = 2; /* conservative */ - if (k > 0) { - ds = tens[k & 0xf]; - j = k >> 4; - if (j & Bletch) { - /* prevent overflows */ - j &= Bletch - 1; - dval(d) /= bigtens[n_bigtens - 1]; - ieps++; - } - for (; j; j >>= 1, i++) { - if (j & 1) { - ieps++; - ds *= bigtens[i]; - } - } - dval(d) /= ds; - } else if ((j1 = -k)) { - dval(d) *= tens[j1 & 0xf]; - for (j = j1 >> 4; j; j >>= 1, i++) { - if (j & 1) { - ieps++; - dval(d) *= bigtens[i]; - } - } - } - if (k_check && dval(d) < 1. && ilim > 0) { - if (ilim1 <= 0) - goto fast_failed; - ilim = ilim1; - k--; - dval(d) *= 10.; - ieps++; - } - dval(eps) = (ieps * dval(d)) + 7.; - word0(eps) -= (P - 1) * Exp_msk1; - if (ilim == 0) { - S = mhi = 0; - dval(d) -= 5.; - if (dval(d) > dval(eps)) - goto one_digit; - if (dval(d) < -dval(eps)) - goto no_digits; - goto fast_failed; - } -#ifndef No_leftright - if (leftright) { - /* Use Steele & White method of only - * generating digits needed. - */ - dval(eps) = (0.5 / tens[ilim - 1]) - dval(eps); - for (i = 0;;) { - L = (long int)dval(d); - dval(d) -= L; - *s++ = '0' + (int)L; - if (dval(d) < dval(eps)) - goto ret1; - if (1. - dval(d) < dval(eps)) - goto bump_up; - if (++i >= ilim) - break; - dval(eps) *= 10.; - dval(d) *= 10.; - } - } else { -#endif - /* Generate ilim digits, then fix them up. */ - dval(eps) *= tens[ilim - 1]; - for (i = 1;; i++, dval(d) *= 10.) { - L = (int32_t)(dval(d)); - if (!(dval(d) -= L)) - ilim = i; - *s++ = '0' + (int)L; - if (i == ilim) { - if (dval(d) > 0.5 + dval(eps)) - goto bump_up; - else if (dval(d) < 0.5 - dval(eps)) { - while (*--s == '0') { } - s++; - goto ret1; - } - break; - } - } -#ifndef No_leftright - } -#endif -fast_failed: - s = s0; - dval(d) = dval(d2); - k = k0; - ilim = ilim0; - } - - /* Do we have a "small" integer? */ - - if (be >= 0 && k <= Int_max) { - /* Yes. */ - ds = tens[k]; - if (ndigits < 0 && ilim <= 0) { - S = mhi = 0; - if (ilim < 0 || dval(d) <= 5 * ds) - goto no_digits; - goto one_digit; - } - for (i = 1;; i++, dval(d) *= 10.) { - L = (int32_t)(dval(d) / ds); - dval(d) -= L * ds; -#ifdef Check_FLT_ROUNDS - /* If FLT_ROUNDS == 2, L will usually be high by 1 */ - if (dval(d) < 0) { - L--; - dval(d) += ds; - } -#endif - *s++ = '0' + (int)L; - if (!dval(d)) { -#ifdef SET_INEXACT - inexact = 0; -#endif - break; - } - if (i == ilim) { - dval(d) += dval(d); - if (dval(d) > ds || dval(d) == ds && L & 1) { -bump_up: - while (*--s == '9') - if (s == s0) { - k++; - *s = '0'; - break; - } - ++*s++; - } - break; - } - } - goto ret1; - } - - m2 = b2; - m5 = b5; - mhi = mlo = 0; - if (leftright) { - i = -#ifndef Sudden_Underflow - denorm ? be + (Bias + (P - 1) - 1 + 1) : -#endif - 1 + P - bbits; - b2 += i; - s2 += i; - mhi = i2b(1); - } - if (m2 > 0 && s2 > 0) { - i = m2 < s2 ? m2 : s2; - b2 -= i; - m2 -= i; - s2 -= i; - } - if (b5 > 0) { - if (leftright) { - if (m5 > 0) { - mhi = pow5mult(mhi, m5); - b1 = mult(mhi, b); - Bfree(b); - b = b1; - } - if ((j = b5 - m5)) - b = pow5mult(b, j); - } else - b = pow5mult(b, b5); - } - S = i2b(1); - if (s5 > 0) - S = pow5mult(S, s5); - - /* Check for special case that d is a normalized power of 2. */ - - spec_case = 0; - if (!word1(d) && !(word0(d) & Bndry_mask) -#ifndef Sudden_Underflow - && word0(d) & (Exp_mask & ~Exp_msk1) -#endif - ) { - /* The special case */ - b2 += Log2P; - s2 += Log2P; - spec_case = 1; - } - - /* Arrange for convenient computation of quotients: - * shift left if necessary so divisor has 4 leading 0 bits. - * - * Perhaps we should just compute leading 28 bits of S once - * and for all and pass them and a shift to quorem, so it - * can do shifts and ors to compute the numerator for q. - */ -#ifdef Pack_32 - if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds - 1]) : 1) + s2) & 0x1f)) - i = 32 - i; -#else - if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds - 1]) : 1) + s2) & 0xf)) - i = 16 - i; -#endif - if (i > 4) { - i -= 4; - b2 += i; - m2 += i; - s2 += i; - } else if (i < 4) { - i += 28; - b2 += i; - m2 += i; - s2 += i; - } - if (b2 > 0) - b = lshift(b, b2); - if (s2 > 0) - S = lshift(S, s2); - if (k_check) { - if (cmp(b,S) < 0) { - k--; - b = multadd(b, 10, 0); /* we botched the k estimate */ - if (leftright) - mhi = multadd(mhi, 10, 0); - ilim = ilim1; - } - } - - if (leftright) { - if (m2 > 0) - mhi = lshift(mhi, m2); - - /* Compute mlo -- check for special case - * that d is a normalized power of 2. - */ - - mlo = mhi; - if (spec_case) { - mhi = Balloc(mhi->k); - Bcopy(mhi, mlo); - mhi = lshift(mhi, Log2P); - } - - for (i = 1;;i++) { - dig = quorem(b,S) + '0'; - /* Do we yet have the shortest decimal string - * that will round to d? - */ - j = cmp(b, mlo); - delta = diff(S, mhi); - j1 = delta->sign ? 1 : cmp(b, delta); - Bfree(delta); - if (j1 == 0 && !(word1(d) & 1)) { - if (dig == '9') - goto round_9_up; - if (j > 0) - dig++; -#ifdef SET_INEXACT - else if (!b->x[0] && b->wds <= 1) - inexact = 0; -#endif - *s++ = dig; - goto ret; - } - if (j < 0 || j == 0 && !(word1(d) & 1)) { - if (!b->x[0] && b->wds <= 1) { -#ifdef SET_INEXACT - inexact = 0; -#endif - goto accept_dig; - } - if (j1 > 0) { - b = lshift(b, 1); - j1 = cmp(b, S); - if ((j1 > 0 || j1 == 0 && dig & 1) && dig++ == '9') - goto round_9_up; - } -accept_dig: - *s++ = dig; - goto ret; - } - if (j1 > 0) { - if (dig == '9') { /* possible if i == 1 */ -round_9_up: - *s++ = '9'; - goto roundoff; - } - *s++ = dig + 1; - goto ret; - } - *s++ = dig; - if (i == ilim) - break; - b = multadd(b, 10, 0); - if (mlo == mhi) - mlo = mhi = multadd(mhi, 10, 0); - else { - mlo = multadd(mlo, 10, 0); - mhi = multadd(mhi, 10, 0); - } - } - } else - for (i = 1;; i++) { - *s++ = dig = quorem(b,S) + '0'; - if (!b->x[0] && b->wds <= 1) { -#ifdef SET_INEXACT - inexact = 0; -#endif - goto ret; - } - if (i >= ilim) - break; - b = multadd(b, 10, 0); - } - - /* Round off last digit */ - - b = lshift(b, 1); - j = cmp(b, S); - if (j > 0 || j == 0 && dig & 1) { -roundoff: - while (*--s == '9') - if (s == s0) { - k++; - *s++ = '1'; - goto ret; - } - ++*s++; - } else { - while (*--s == '0') { } - s++; - } - goto ret; -no_digits: - k = -1 - ndigits; - goto ret; -one_digit: - *s++ = '1'; - k++; - goto ret; -ret: - Bfree(S); - if (mhi) { - if (mlo && mlo != mhi) - Bfree(mlo); - Bfree(mhi); - } -ret1: -#ifdef SET_INEXACT - if (inexact) { - if (!oldinexact) { - word0(d) = Exp_1 + (70 << Exp_shift); - word1(d) = 0; - dval(d) += 1.; - } - } else if (!oldinexact) - clear_inexact(); -#endif - Bfree(b); - *s = 0; - *decpt = k + 1; - if (rve) - *rve = s; - return s0; -} - -} // namespace JSC diff --git a/JavaScriptCore/kjs/dtoa.h b/JavaScriptCore/kjs/dtoa.h deleted file mode 100644 index 690ebc8..0000000 --- a/JavaScriptCore/kjs/dtoa.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2003, 2008 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#ifndef KJS_dtoa_h -#define KJS_dtoa_h - -namespace WTF { - class Mutex; -} - -namespace JSC { - - extern WTF::Mutex* s_dtoaP5Mutex; - - double strtod(const char* s00, char** se); - char* dtoa(double d, int ndigits, int* decpt, int* sign, char** rve); - void freedtoa(char* s); - -} // namespace JSC - -#endif /* KJS_dtoa_h */ diff --git a/JavaScriptCore/kjs/grammar.y b/JavaScriptCore/kjs/grammar.y deleted file mode 100644 index 370798d..0000000 --- a/JavaScriptCore/kjs/grammar.y +++ /dev/null @@ -1,1511 +0,0 @@ -%pure_parser - -%{ - -/* - * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2007 Eric Seidel <eric@webkit.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "config.h" - -#include <string.h> -#include <stdlib.h> -#include "JSValue.h" -#include "JSObject.h" -#include "nodes.h" -#include "lexer.h" -#include "JSString.h" -#include "JSGlobalData.h" -#include "CommonIdentifiers.h" -#include "NodeInfo.h" -#include "Parser.h" -#include <wtf/MathExtras.h> - -#define YYMAXDEPTH 10000 -#define YYENABLE_NLS 0 - -/* default values for bison */ -#define YYDEBUG 0 // Set to 1 to debug a parse error. -#define kjsyydebug 0 // Set to 1 to debug a parse error. -#if !PLATFORM(DARWIN) - // avoid triggering warnings in older bison -#define YYERROR_VERBOSE -#endif - -int kjsyylex(void* lvalp, void* llocp, void* globalPtr); -int kjsyyerror(const char*); -static inline bool allowAutomaticSemicolon(JSC::Lexer&, int); - -#define GLOBAL_DATA static_cast<JSGlobalData*>(globalPtr) -#define LEXER (GLOBAL_DATA->lexer) - -#define AUTO_SEMICOLON do { if (!allowAutomaticSemicolon(*LEXER, yychar)) YYABORT; } while (0) -#define SET_EXCEPTION_LOCATION(node, start, divot, end) node->setExceptionSourceCode((divot), (divot) - (start), (end) - (divot)) -#define DBG(l, s, e) (l)->setLoc((s).first_line, (e).last_line) - -using namespace JSC; -using namespace std; - -static ExpressionNode* makeAssignNode(void*, ExpressionNode* loc, Operator, ExpressionNode* expr, bool locHasAssignments, bool exprHasAssignments, int start, int divot, int end); -static ExpressionNode* makePrefixNode(void*, ExpressionNode* expr, Operator, int start, int divot, int end); -static ExpressionNode* makePostfixNode(void*, ExpressionNode* expr, Operator, int start, int divot, int end); -static PropertyNode* makeGetterOrSetterPropertyNode(void*, const Identifier &getOrSet, const Identifier& name, ParameterNode*, FunctionBodyNode*, const SourceCode&); -static ExpressionNodeInfo makeFunctionCallNode(void*, ExpressionNodeInfo func, ArgumentsNodeInfo, int start, int divot, int end); -static ExpressionNode* makeTypeOfNode(void*, ExpressionNode*); -static ExpressionNode* makeDeleteNode(void*, ExpressionNode*, int start, int divot, int end); -static ExpressionNode* makeNegateNode(void*, ExpressionNode*); -static NumberNode* makeNumberNode(void*, double); -static ExpressionNode* makeBitwiseNotNode(void*, ExpressionNode*); -static ExpressionNode* makeMultNode(void*, ExpressionNode*, ExpressionNode*, bool rightHasAssignments); -static ExpressionNode* makeDivNode(void*, ExpressionNode*, ExpressionNode*, bool rightHasAssignments); -static ExpressionNode* makeAddNode(void*, ExpressionNode*, ExpressionNode*, bool rightHasAssignments); -static ExpressionNode* makeSubNode(void*, ExpressionNode*, ExpressionNode*, bool rightHasAssignments); -static ExpressionNode* makeLeftShiftNode(void*, ExpressionNode*, ExpressionNode*, bool rightHasAssignments); -static ExpressionNode* makeRightShiftNode(void*, ExpressionNode*, ExpressionNode*, bool rightHasAssignments); -static StatementNode* makeVarStatementNode(void*, ExpressionNode*); -static ExpressionNode* combineVarInitializers(void*, ExpressionNode* list, AssignResolveNode* init); - -#if COMPILER(MSVC) - -#pragma warning(disable: 4065) -#pragma warning(disable: 4244) -#pragma warning(disable: 4702) - -// At least some of the time, the declarations of malloc and free that bison -// generates are causing warnings. A way to avoid this is to explicitly define -// the macros so that bison doesn't try to declare malloc and free. -#define YYMALLOC malloc -#define YYFREE free - -#endif - -#define YYPARSE_PARAM globalPtr -#define YYLEX_PARAM globalPtr - -template <typename T> NodeDeclarationInfo<T> createNodeDeclarationInfo(T node, ParserRefCountedData<DeclarationStacks::VarStack>* varDecls, - ParserRefCountedData<DeclarationStacks::FunctionStack>* funcDecls, - CodeFeatures info, - int numConstants) -{ - ASSERT((info & ~AllFeatures) == 0); - NodeDeclarationInfo<T> result = {node, varDecls, funcDecls, info, numConstants}; - return result; -} - -template <typename T> NodeInfo<T> createNodeInfo(T node, CodeFeatures info, int numConstants) -{ - ASSERT((info & ~AllFeatures) == 0); - NodeInfo<T> result = {node, info, numConstants}; - return result; -} - -template <typename T> T mergeDeclarationLists(T decls1, T decls2) -{ - // decls1 or both are null - if (!decls1) - return decls2; - // only decls1 is non-null - if (!decls2) - return decls1; - - // Both are non-null - decls1->data.append(decls2->data); - - // We manually release the declaration lists to avoid accumulating many many - // unused heap allocated vectors - decls2->ref(); - decls2->deref(); - return decls1; -} - -static void appendToVarDeclarationList(void* globalPtr, ParserRefCountedData<DeclarationStacks::VarStack>*& varDecls, const Identifier& ident, unsigned attrs) -{ - if (!varDecls) - varDecls = new ParserRefCountedData<DeclarationStacks::VarStack>(GLOBAL_DATA); - - varDecls->data.append(make_pair(ident, attrs)); - -} - -static inline void appendToVarDeclarationList(void* globalPtr, ParserRefCountedData<DeclarationStacks::VarStack>*& varDecls, ConstDeclNode* decl) -{ - unsigned attrs = DeclarationStacks::IsConstant; - if (decl->m_init) - attrs |= DeclarationStacks::HasInitializer; - appendToVarDeclarationList(globalPtr, varDecls, decl->m_ident, attrs); -} - -%} - -%union { - int intValue; - double doubleValue; - Identifier* ident; - - // expression subtrees - ExpressionNodeInfo expressionNode; - FuncDeclNodeInfo funcDeclNode; - PropertyNodeInfo propertyNode; - ArgumentsNodeInfo argumentsNode; - ConstDeclNodeInfo constDeclNode; - CaseBlockNodeInfo caseBlockNode; - CaseClauseNodeInfo caseClauseNode; - FuncExprNodeInfo funcExprNode; - - // statement nodes - StatementNodeInfo statementNode; - FunctionBodyNode* functionBodyNode; - ProgramNode* programNode; - - SourceElementsInfo sourceElements; - PropertyListInfo propertyList; - ArgumentListInfo argumentList; - VarDeclListInfo varDeclList; - ConstDeclListInfo constDeclList; - ClauseListInfo clauseList; - ElementListInfo elementList; - ParameterListInfo parameterList; - - Operator op; -} - -%start Program - -/* literals */ -%token NULLTOKEN TRUETOKEN FALSETOKEN - -/* keywords */ -%token BREAK CASE DEFAULT FOR NEW VAR CONSTTOKEN CONTINUE -%token FUNCTION RETURN VOIDTOKEN DELETETOKEN -%token IF THISTOKEN DO WHILE INTOKEN INSTANCEOF TYPEOF -%token SWITCH WITH RESERVED -%token THROW TRY CATCH FINALLY -%token DEBUGGER - -/* give an if without an else higher precedence than an else to resolve the ambiguity */ -%nonassoc IF_WITHOUT_ELSE -%nonassoc ELSE - -/* punctuators */ -%token EQEQ NE /* == and != */ -%token STREQ STRNEQ /* === and !== */ -%token LE GE /* < and > */ -%token OR AND /* || and && */ -%token PLUSPLUS MINUSMINUS /* ++ and -- */ -%token LSHIFT /* << */ -%token RSHIFT URSHIFT /* >> and >>> */ -%token PLUSEQUAL MINUSEQUAL /* += and -= */ -%token MULTEQUAL DIVEQUAL /* *= and /= */ -%token LSHIFTEQUAL /* <<= */ -%token RSHIFTEQUAL URSHIFTEQUAL /* >>= and >>>= */ -%token ANDEQUAL MODEQUAL /* &= and %= */ -%token XOREQUAL OREQUAL /* ^= and |= */ -%token <intValue> OPENBRACE /* { (with char offset) */ -%token <intValue> CLOSEBRACE /* { (with char offset) */ - -/* terminal types */ -%token <doubleValue> NUMBER -%token <ident> IDENT STRING - -/* automatically inserted semicolon */ -%token AUTOPLUSPLUS AUTOMINUSMINUS - -/* non-terminal types */ -%type <expressionNode> Literal ArrayLiteral - -%type <expressionNode> PrimaryExpr PrimaryExprNoBrace -%type <expressionNode> MemberExpr MemberExprNoBF /* BF => brace or function */ -%type <expressionNode> NewExpr NewExprNoBF -%type <expressionNode> CallExpr CallExprNoBF -%type <expressionNode> LeftHandSideExpr LeftHandSideExprNoBF -%type <expressionNode> PostfixExpr PostfixExprNoBF -%type <expressionNode> UnaryExpr UnaryExprNoBF UnaryExprCommon -%type <expressionNode> MultiplicativeExpr MultiplicativeExprNoBF -%type <expressionNode> AdditiveExpr AdditiveExprNoBF -%type <expressionNode> ShiftExpr ShiftExprNoBF -%type <expressionNode> RelationalExpr RelationalExprNoIn RelationalExprNoBF -%type <expressionNode> EqualityExpr EqualityExprNoIn EqualityExprNoBF -%type <expressionNode> BitwiseANDExpr BitwiseANDExprNoIn BitwiseANDExprNoBF -%type <expressionNode> BitwiseXORExpr BitwiseXORExprNoIn BitwiseXORExprNoBF -%type <expressionNode> BitwiseORExpr BitwiseORExprNoIn BitwiseORExprNoBF -%type <expressionNode> LogicalANDExpr LogicalANDExprNoIn LogicalANDExprNoBF -%type <expressionNode> LogicalORExpr LogicalORExprNoIn LogicalORExprNoBF -%type <expressionNode> ConditionalExpr ConditionalExprNoIn ConditionalExprNoBF -%type <expressionNode> AssignmentExpr AssignmentExprNoIn AssignmentExprNoBF -%type <expressionNode> Expr ExprNoIn ExprNoBF - -%type <expressionNode> ExprOpt ExprNoInOpt - -%type <statementNode> Statement Block -%type <statementNode> VariableStatement ConstStatement EmptyStatement ExprStatement -%type <statementNode> IfStatement IterationStatement ContinueStatement -%type <statementNode> BreakStatement ReturnStatement WithStatement -%type <statementNode> SwitchStatement LabelledStatement -%type <statementNode> ThrowStatement TryStatement -%type <statementNode> DebuggerStatement -%type <statementNode> SourceElement - -%type <expressionNode> Initializer InitializerNoIn -%type <funcDeclNode> FunctionDeclaration -%type <funcExprNode> FunctionExpr -%type <functionBodyNode> FunctionBody -%type <sourceElements> SourceElements -%type <parameterList> FormalParameterList -%type <op> AssignmentOperator -%type <argumentsNode> Arguments -%type <argumentList> ArgumentList -%type <varDeclList> VariableDeclarationList VariableDeclarationListNoIn -%type <constDeclList> ConstDeclarationList -%type <constDeclNode> ConstDeclaration -%type <caseBlockNode> CaseBlock -%type <caseClauseNode> CaseClause DefaultClause -%type <clauseList> CaseClauses CaseClausesOpt -%type <intValue> Elision ElisionOpt -%type <elementList> ElementList -%type <propertyNode> Property -%type <propertyList> PropertyList -%% - -Literal: - NULLTOKEN { $$ = createNodeInfo<ExpressionNode*>(new NullNode(GLOBAL_DATA), 0, 1); } - | TRUETOKEN { $$ = createNodeInfo<ExpressionNode*>(new BooleanNode(GLOBAL_DATA, true), 0, 1); } - | FALSETOKEN { $$ = createNodeInfo<ExpressionNode*>(new BooleanNode(GLOBAL_DATA, false), 0, 1); } - | NUMBER { $$ = createNodeInfo<ExpressionNode*>(makeNumberNode(GLOBAL_DATA, $1), 0, 1); } - | STRING { $$ = createNodeInfo<ExpressionNode*>(new StringNode(GLOBAL_DATA, *$1), 0, 1); } - | '/' /* regexp */ { - Lexer& l = *LEXER; - if (!l.scanRegExp()) - YYABORT; - RegExpNode* node = new RegExpNode(GLOBAL_DATA, l.pattern(), l.flags()); - int size = l.pattern().size() + 2; // + 2 for the two /'s - SET_EXCEPTION_LOCATION(node, @1.first_column, @1.first_column + size, @1.first_column + size); - $$ = createNodeInfo<ExpressionNode*>(node, 0, 0); - } - | DIVEQUAL /* regexp with /= */ { - Lexer& l = *LEXER; - if (!l.scanRegExp()) - YYABORT; - RegExpNode* node = new RegExpNode(GLOBAL_DATA, "=" + l.pattern(), l.flags()); - int size = l.pattern().size() + 2; // + 2 for the two /'s - SET_EXCEPTION_LOCATION(node, @1.first_column, @1.first_column + size, @1.first_column + size); - $$ = createNodeInfo<ExpressionNode*>(node, 0, 0); - } -; - -Property: - IDENT ':' AssignmentExpr { $$ = createNodeInfo<PropertyNode*>(new PropertyNode(GLOBAL_DATA, *$1, $3.m_node, PropertyNode::Constant), $3.m_features, $3.m_numConstants); } - | STRING ':' AssignmentExpr { $$ = createNodeInfo<PropertyNode*>(new PropertyNode(GLOBAL_DATA, *$1, $3.m_node, PropertyNode::Constant), $3.m_features, $3.m_numConstants); } - | NUMBER ':' AssignmentExpr { $$ = createNodeInfo<PropertyNode*>(new PropertyNode(GLOBAL_DATA, Identifier(GLOBAL_DATA, UString::from($1)), $3.m_node, PropertyNode::Constant), $3.m_features, $3.m_numConstants); } - | IDENT IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeInfo<PropertyNode*>(makeGetterOrSetterPropertyNode(globalPtr, *$1, *$2, 0, $6, LEXER->sourceCode($5, $7, @5.first_line)), ClosureFeature, 0); DBG($6, @5, @7); if (!$$.m_node) YYABORT; } - | IDENT IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE - { - $$ = createNodeInfo<PropertyNode*>(makeGetterOrSetterPropertyNode(globalPtr, *$1, *$2, $4.m_node.head, $7, LEXER->sourceCode($6, $8, @6.first_line)), $4.m_features | ClosureFeature, 0); - if ($4.m_features & ArgumentsFeature) - $7->setUsesArguments(); - DBG($7, @6, @8); - if (!$$.m_node) - YYABORT; - } -; - -PropertyList: - Property { $$.m_node.head = new PropertyListNode(GLOBAL_DATA, $1.m_node); - $$.m_node.tail = $$.m_node.head; - $$.m_features = $1.m_features; - $$.m_numConstants = $1.m_numConstants; } - | PropertyList ',' Property { $$.m_node.head = $1.m_node.head; - $$.m_node.tail = new PropertyListNode(GLOBAL_DATA, $3.m_node, $1.m_node.tail); - $$.m_features = $1.m_features | $3.m_features; - $$.m_numConstants = $1.m_numConstants + $3.m_numConstants; } -; - -PrimaryExpr: - PrimaryExprNoBrace - | OPENBRACE CLOSEBRACE { $$ = createNodeInfo<ExpressionNode*>(new ObjectLiteralNode(GLOBAL_DATA), 0, 0); } - | OPENBRACE PropertyList CLOSEBRACE { $$ = createNodeInfo<ExpressionNode*>(new ObjectLiteralNode(GLOBAL_DATA, $2.m_node.head), $2.m_features, $2.m_numConstants); } - /* allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939 */ - | OPENBRACE PropertyList ',' CLOSEBRACE { $$ = createNodeInfo<ExpressionNode*>(new ObjectLiteralNode(GLOBAL_DATA, $2.m_node.head), $2.m_features, $2.m_numConstants); } -; - -PrimaryExprNoBrace: - THISTOKEN { $$ = createNodeInfo<ExpressionNode*>(new ThisNode(GLOBAL_DATA), ThisFeature, 0); } - | Literal - | ArrayLiteral - | IDENT { $$ = createNodeInfo<ExpressionNode*>(new ResolveNode(GLOBAL_DATA, *$1, @1.first_column), (*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0, 0); } - | '(' Expr ')' { $$ = $2; } -; - -ArrayLiteral: - '[' ElisionOpt ']' { $$ = createNodeInfo<ExpressionNode*>(new ArrayNode(GLOBAL_DATA, $2), 0, $2 ? 1 : 0); } - | '[' ElementList ']' { $$ = createNodeInfo<ExpressionNode*>(new ArrayNode(GLOBAL_DATA, $2.m_node.head), $2.m_features, $2.m_numConstants); } - | '[' ElementList ',' ElisionOpt ']' { $$ = createNodeInfo<ExpressionNode*>(new ArrayNode(GLOBAL_DATA, $4, $2.m_node.head), $2.m_features, $4 ? $2.m_numConstants + 1 : $2.m_numConstants); } -; - -ElementList: - ElisionOpt AssignmentExpr { $$.m_node.head = new ElementNode(GLOBAL_DATA, $1, $2.m_node); - $$.m_node.tail = $$.m_node.head; - $$.m_features = $2.m_features; - $$.m_numConstants = $2.m_numConstants; } - | ElementList ',' ElisionOpt AssignmentExpr - { $$.m_node.head = $1.m_node.head; - $$.m_node.tail = new ElementNode(GLOBAL_DATA, $1.m_node.tail, $3, $4.m_node); - $$.m_features = $1.m_features | $4.m_features; - $$.m_numConstants = $1.m_numConstants + $4.m_numConstants; } -; - -ElisionOpt: - /* nothing */ { $$ = 0; } - | Elision -; - -Elision: - ',' { $$ = 1; } - | Elision ',' { $$ = $1 + 1; } -; - -MemberExpr: - PrimaryExpr - | FunctionExpr { $$ = createNodeInfo<ExpressionNode*>($1.m_node, $1.m_features, $1.m_numConstants); } - | MemberExpr '[' Expr ']' { BracketAccessorNode* node = new BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature); - SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @4.last_column); - $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); - } - | MemberExpr '.' IDENT { DotAccessorNode* node = new DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3); - SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @3.last_column); - $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features, $1.m_numConstants); - } - | NEW MemberExpr Arguments { NewExprNode* node = new NewExprNode(GLOBAL_DATA, $2.m_node, $3.m_node); - SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @3.last_column); - $$ = createNodeInfo<ExpressionNode*>(node, $2.m_features | $3.m_features, $2.m_numConstants + $3.m_numConstants); - } -; - -MemberExprNoBF: - PrimaryExprNoBrace - | MemberExprNoBF '[' Expr ']' { BracketAccessorNode* node = new BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature); - SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @4.last_column); - $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); - } - | MemberExprNoBF '.' IDENT { DotAccessorNode* node = new DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3); - SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @3.last_column); - $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features, $1.m_numConstants); - } - | NEW MemberExpr Arguments { NewExprNode* node = new NewExprNode(GLOBAL_DATA, $2.m_node, $3.m_node); - SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @3.last_column); - $$ = createNodeInfo<ExpressionNode*>(node, $2.m_features | $3.m_features, $2.m_numConstants + $3.m_numConstants); - } -; - -NewExpr: - MemberExpr - | NEW NewExpr { NewExprNode* node = new NewExprNode(GLOBAL_DATA, $2.m_node); - SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); - $$ = createNodeInfo<ExpressionNode*>(node, $2.m_features, $2.m_numConstants); - } -; - -NewExprNoBF: - MemberExprNoBF - | NEW NewExpr { NewExprNode* node = new NewExprNode(GLOBAL_DATA, $2.m_node); - SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); - $$ = createNodeInfo<ExpressionNode*>(node, $2.m_features, $2.m_numConstants); - } -; - -CallExpr: - MemberExpr Arguments { $$ = makeFunctionCallNode(globalPtr, $1, $2, @1.first_column, @1.last_column, @2.last_column); } - | CallExpr Arguments { $$ = makeFunctionCallNode(globalPtr, $1, $2, @1.first_column, @1.last_column, @2.last_column); } - | CallExpr '[' Expr ']' { BracketAccessorNode* node = new BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature); - SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @4.last_column); - $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); - } - | CallExpr '.' IDENT { DotAccessorNode* node = new DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3); - SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @3.last_column); - $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features, $1.m_numConstants); } -; - -CallExprNoBF: - MemberExprNoBF Arguments { $$ = makeFunctionCallNode(globalPtr, $1, $2, @1.first_column, @1.last_column, @2.last_column); } - | CallExprNoBF Arguments { $$ = makeFunctionCallNode(globalPtr, $1, $2, @1.first_column, @1.last_column, @2.last_column); } - | CallExprNoBF '[' Expr ']' { BracketAccessorNode* node = new BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature); - SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @4.last_column); - $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); - } - | CallExprNoBF '.' IDENT { DotAccessorNode* node = new DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3); - SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @3.last_column); - $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features, $1.m_numConstants); - } -; - -Arguments: - '(' ')' { $$ = createNodeInfo<ArgumentsNode*>(new ArgumentsNode(GLOBAL_DATA), 0, 0); } - | '(' ArgumentList ')' { $$ = createNodeInfo<ArgumentsNode*>(new ArgumentsNode(GLOBAL_DATA, $2.m_node.head), $2.m_features, $2.m_numConstants); } -; - -ArgumentList: - AssignmentExpr { $$.m_node.head = new ArgumentListNode(GLOBAL_DATA, $1.m_node); - $$.m_node.tail = $$.m_node.head; - $$.m_features = $1.m_features; - $$.m_numConstants = $1.m_numConstants; } - | ArgumentList ',' AssignmentExpr { $$.m_node.head = $1.m_node.head; - $$.m_node.tail = new ArgumentListNode(GLOBAL_DATA, $1.m_node.tail, $3.m_node); - $$.m_features = $1.m_features | $3.m_features; - $$.m_numConstants = $1.m_numConstants + $3.m_numConstants; } -; - -LeftHandSideExpr: - NewExpr - | CallExpr -; - -LeftHandSideExprNoBF: - NewExprNoBF - | CallExprNoBF -; - -PostfixExpr: - LeftHandSideExpr - | LeftHandSideExpr PLUSPLUS { $$ = createNodeInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpPlusPlus, @1.first_column, @1.last_column, @2.last_column), $1.m_features | AssignFeature, $1.m_numConstants); } - | LeftHandSideExpr MINUSMINUS { $$ = createNodeInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpMinusMinus, @1.first_column, @1.last_column, @2.last_column), $1.m_features | AssignFeature, $1.m_numConstants); } -; - -PostfixExprNoBF: - LeftHandSideExprNoBF - | LeftHandSideExprNoBF PLUSPLUS { $$ = createNodeInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpPlusPlus, @1.first_column, @1.last_column, @2.last_column), $1.m_features | AssignFeature, $1.m_numConstants); } - | LeftHandSideExprNoBF MINUSMINUS { $$ = createNodeInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpMinusMinus, @1.first_column, @1.last_column, @2.last_column), $1.m_features | AssignFeature, $1.m_numConstants); } -; - -UnaryExprCommon: - DELETETOKEN UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeDeleteNode(GLOBAL_DATA, $2.m_node, @1.first_column, @2.last_column, @2.last_column), $2.m_features, $2.m_numConstants); } - | VOIDTOKEN UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(new VoidNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants + 1); } - | TYPEOF UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeTypeOfNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants); } - | PLUSPLUS UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpPlusPlus, @1.first_column, @2.first_column + 1, @2.last_column), $2.m_features | AssignFeature, $2.m_numConstants); } - | AUTOPLUSPLUS UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpPlusPlus, @1.first_column, @2.first_column + 1, @2.last_column), $2.m_features | AssignFeature, $2.m_numConstants); } - | MINUSMINUS UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpMinusMinus, @1.first_column, @2.first_column + 1, @2.last_column), $2.m_features | AssignFeature, $2.m_numConstants); } - | AUTOMINUSMINUS UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpMinusMinus, @1.first_column, @2.first_column + 1, @2.last_column), $2.m_features | AssignFeature, $2.m_numConstants); } - | '+' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(new UnaryPlusNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants); } - | '-' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeNegateNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants); } - | '~' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeBitwiseNotNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants); } - | '!' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(new LogicalNotNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants); } - -UnaryExpr: - PostfixExpr - | UnaryExprCommon -; - -UnaryExprNoBF: - PostfixExprNoBF - | UnaryExprCommon -; - -MultiplicativeExpr: - UnaryExpr - | MultiplicativeExpr '*' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeMultNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | MultiplicativeExpr '/' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeDivNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | MultiplicativeExpr '%' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(new ModNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -MultiplicativeExprNoBF: - UnaryExprNoBF - | MultiplicativeExprNoBF '*' UnaryExpr - { $$ = createNodeInfo<ExpressionNode*>(makeMultNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | MultiplicativeExprNoBF '/' UnaryExpr - { $$ = createNodeInfo<ExpressionNode*>(makeDivNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | MultiplicativeExprNoBF '%' UnaryExpr - { $$ = createNodeInfo<ExpressionNode*>(new ModNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -AdditiveExpr: - MultiplicativeExpr - | AdditiveExpr '+' MultiplicativeExpr { $$ = createNodeInfo<ExpressionNode*>(makeAddNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | AdditiveExpr '-' MultiplicativeExpr { $$ = createNodeInfo<ExpressionNode*>(makeSubNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -AdditiveExprNoBF: - MultiplicativeExprNoBF - | AdditiveExprNoBF '+' MultiplicativeExpr - { $$ = createNodeInfo<ExpressionNode*>(makeAddNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | AdditiveExprNoBF '-' MultiplicativeExpr - { $$ = createNodeInfo<ExpressionNode*>(makeSubNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -ShiftExpr: - AdditiveExpr - | ShiftExpr LSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(makeLeftShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | ShiftExpr RSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(makeRightShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | ShiftExpr URSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(new UnsignedRightShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -ShiftExprNoBF: - AdditiveExprNoBF - | ShiftExprNoBF LSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(makeLeftShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | ShiftExprNoBF RSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(makeRightShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | ShiftExprNoBF URSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(new UnsignedRightShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -RelationalExpr: - ShiftExpr - | RelationalExpr '<' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new LessNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | RelationalExpr '>' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new GreaterNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | RelationalExpr LE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new LessEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | RelationalExpr GE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new GreaterEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | RelationalExpr INSTANCEOF ShiftExpr { InstanceOfNode* node = new InstanceOfNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature); - SET_EXCEPTION_LOCATION(node, @1.first_column, @3.first_column, @3.last_column); - $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | RelationalExpr INTOKEN ShiftExpr { InNode* node = new InNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature); - SET_EXCEPTION_LOCATION(node, @1.first_column, @3.first_column, @3.last_column); - $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -RelationalExprNoIn: - ShiftExpr - | RelationalExprNoIn '<' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new LessNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | RelationalExprNoIn '>' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new GreaterNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | RelationalExprNoIn LE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new LessEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | RelationalExprNoIn GE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new GreaterEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | RelationalExprNoIn INSTANCEOF ShiftExpr - { InstanceOfNode* node = new InstanceOfNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature); - SET_EXCEPTION_LOCATION(node, @1.first_column, @3.first_column, @3.last_column); - $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -RelationalExprNoBF: - ShiftExprNoBF - | RelationalExprNoBF '<' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new LessNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | RelationalExprNoBF '>' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new GreaterNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | RelationalExprNoBF LE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new LessEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | RelationalExprNoBF GE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new GreaterEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | RelationalExprNoBF INSTANCEOF ShiftExpr - { InstanceOfNode* node = new InstanceOfNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature); - SET_EXCEPTION_LOCATION(node, @1.first_column, @3.first_column, @3.last_column); - $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | RelationalExprNoBF INTOKEN ShiftExpr - { InNode* node = new InNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature); - SET_EXCEPTION_LOCATION(node, @1.first_column, @3.first_column, @3.last_column); - $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -EqualityExpr: - RelationalExpr - | EqualityExpr EQEQ RelationalExpr { $$ = createNodeInfo<ExpressionNode*>(new EqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | EqualityExpr NE RelationalExpr { $$ = createNodeInfo<ExpressionNode*>(new NotEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | EqualityExpr STREQ RelationalExpr { $$ = createNodeInfo<ExpressionNode*>(new StrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | EqualityExpr STRNEQ RelationalExpr { $$ = createNodeInfo<ExpressionNode*>(new NotStrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -EqualityExprNoIn: - RelationalExprNoIn - | EqualityExprNoIn EQEQ RelationalExprNoIn - { $$ = createNodeInfo<ExpressionNode*>(new EqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | EqualityExprNoIn NE RelationalExprNoIn - { $$ = createNodeInfo<ExpressionNode*>(new NotEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | EqualityExprNoIn STREQ RelationalExprNoIn - { $$ = createNodeInfo<ExpressionNode*>(new StrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | EqualityExprNoIn STRNEQ RelationalExprNoIn - { $$ = createNodeInfo<ExpressionNode*>(new NotStrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -EqualityExprNoBF: - RelationalExprNoBF - | EqualityExprNoBF EQEQ RelationalExpr - { $$ = createNodeInfo<ExpressionNode*>(new EqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | EqualityExprNoBF NE RelationalExpr { $$ = createNodeInfo<ExpressionNode*>(new NotEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | EqualityExprNoBF STREQ RelationalExpr - { $$ = createNodeInfo<ExpressionNode*>(new StrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } - | EqualityExprNoBF STRNEQ RelationalExpr - { $$ = createNodeInfo<ExpressionNode*>(new NotStrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -BitwiseANDExpr: - EqualityExpr - | BitwiseANDExpr '&' EqualityExpr { $$ = createNodeInfo<ExpressionNode*>(new BitAndNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -BitwiseANDExprNoIn: - EqualityExprNoIn - | BitwiseANDExprNoIn '&' EqualityExprNoIn - { $$ = createNodeInfo<ExpressionNode*>(new BitAndNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -BitwiseANDExprNoBF: - EqualityExprNoBF - | BitwiseANDExprNoBF '&' EqualityExpr { $$ = createNodeInfo<ExpressionNode*>(new BitAndNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -BitwiseXORExpr: - BitwiseANDExpr - | BitwiseXORExpr '^' BitwiseANDExpr { $$ = createNodeInfo<ExpressionNode*>(new BitXOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -BitwiseXORExprNoIn: - BitwiseANDExprNoIn - | BitwiseXORExprNoIn '^' BitwiseANDExprNoIn - { $$ = createNodeInfo<ExpressionNode*>(new BitXOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -BitwiseXORExprNoBF: - BitwiseANDExprNoBF - | BitwiseXORExprNoBF '^' BitwiseANDExpr - { $$ = createNodeInfo<ExpressionNode*>(new BitXOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -BitwiseORExpr: - BitwiseXORExpr - | BitwiseORExpr '|' BitwiseXORExpr { $$ = createNodeInfo<ExpressionNode*>(new BitOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -BitwiseORExprNoIn: - BitwiseXORExprNoIn - | BitwiseORExprNoIn '|' BitwiseXORExprNoIn - { $$ = createNodeInfo<ExpressionNode*>(new BitOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -BitwiseORExprNoBF: - BitwiseXORExprNoBF - | BitwiseORExprNoBF '|' BitwiseXORExpr - { $$ = createNodeInfo<ExpressionNode*>(new BitOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -LogicalANDExpr: - BitwiseORExpr - | LogicalANDExpr AND BitwiseORExpr { $$ = createNodeInfo<ExpressionNode*>(new LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalAnd), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -LogicalANDExprNoIn: - BitwiseORExprNoIn - | LogicalANDExprNoIn AND BitwiseORExprNoIn - { $$ = createNodeInfo<ExpressionNode*>(new LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalAnd), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -LogicalANDExprNoBF: - BitwiseORExprNoBF - | LogicalANDExprNoBF AND BitwiseORExpr - { $$ = createNodeInfo<ExpressionNode*>(new LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalAnd), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -LogicalORExpr: - LogicalANDExpr - | LogicalORExpr OR LogicalANDExpr { $$ = createNodeInfo<ExpressionNode*>(new LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalOr), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -LogicalORExprNoIn: - LogicalANDExprNoIn - | LogicalORExprNoIn OR LogicalANDExprNoIn - { $$ = createNodeInfo<ExpressionNode*>(new LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalOr), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -LogicalORExprNoBF: - LogicalANDExprNoBF - | LogicalORExprNoBF OR LogicalANDExpr { $$ = createNodeInfo<ExpressionNode*>(new LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalOr), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -ConditionalExpr: - LogicalORExpr - | LogicalORExpr '?' AssignmentExpr ':' AssignmentExpr - { $$ = createNodeInfo<ExpressionNode*>(new ConditionalNode(GLOBAL_DATA, $1.m_node, $3.m_node, $5.m_node), $1.m_features | $3.m_features | $5.m_features, $1.m_numConstants + $3.m_numConstants + $5.m_numConstants); } -; - -ConditionalExprNoIn: - LogicalORExprNoIn - | LogicalORExprNoIn '?' AssignmentExprNoIn ':' AssignmentExprNoIn - { $$ = createNodeInfo<ExpressionNode*>(new ConditionalNode(GLOBAL_DATA, $1.m_node, $3.m_node, $5.m_node), $1.m_features | $3.m_features | $5.m_features, $1.m_numConstants + $3.m_numConstants + $5.m_numConstants); } -; - -ConditionalExprNoBF: - LogicalORExprNoBF - | LogicalORExprNoBF '?' AssignmentExpr ':' AssignmentExpr - { $$ = createNodeInfo<ExpressionNode*>(new ConditionalNode(GLOBAL_DATA, $1.m_node, $3.m_node, $5.m_node), $1.m_features | $3.m_features | $5.m_features, $1.m_numConstants + $3.m_numConstants + $5.m_numConstants); } -; - -AssignmentExpr: - ConditionalExpr - | LeftHandSideExpr AssignmentOperator AssignmentExpr - { $$ = createNodeInfo<ExpressionNode*>(makeAssignNode(GLOBAL_DATA, $1.m_node, $2, $3.m_node, $1.m_features & AssignFeature, $3.m_features & AssignFeature, - @1.first_column, @2.first_column + 1, @3.last_column), $1.m_features | $3.m_features | AssignFeature, $1.m_numConstants + $3.m_numConstants); - } -; - -AssignmentExprNoIn: - ConditionalExprNoIn - | LeftHandSideExpr AssignmentOperator AssignmentExprNoIn - { $$ = createNodeInfo<ExpressionNode*>(makeAssignNode(GLOBAL_DATA, $1.m_node, $2, $3.m_node, $1.m_features & AssignFeature, $3.m_features & AssignFeature, - @1.first_column, @2.first_column + 1, @3.last_column), $1.m_features | $3.m_features | AssignFeature, $1.m_numConstants + $3.m_numConstants); - } -; - -AssignmentExprNoBF: - ConditionalExprNoBF - | LeftHandSideExprNoBF AssignmentOperator AssignmentExpr - { $$ = createNodeInfo<ExpressionNode*>(makeAssignNode(GLOBAL_DATA, $1.m_node, $2, $3.m_node, $1.m_features & AssignFeature, $3.m_features & AssignFeature, - @1.first_column, @2.first_column + 1, @3.last_column), $1.m_features | $3.m_features | AssignFeature, $1.m_numConstants + $3.m_numConstants); - } -; - -AssignmentOperator: - '=' { $$ = OpEqual; } - | PLUSEQUAL { $$ = OpPlusEq; } - | MINUSEQUAL { $$ = OpMinusEq; } - | MULTEQUAL { $$ = OpMultEq; } - | DIVEQUAL { $$ = OpDivEq; } - | LSHIFTEQUAL { $$ = OpLShift; } - | RSHIFTEQUAL { $$ = OpRShift; } - | URSHIFTEQUAL { $$ = OpURShift; } - | ANDEQUAL { $$ = OpAndEq; } - | XOREQUAL { $$ = OpXOrEq; } - | OREQUAL { $$ = OpOrEq; } - | MODEQUAL { $$ = OpModEq; } -; - -Expr: - AssignmentExpr - | Expr ',' AssignmentExpr { $$ = createNodeInfo<ExpressionNode*>(new CommaNode(GLOBAL_DATA, $1.m_node, $3.m_node), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -ExprNoIn: - AssignmentExprNoIn - | ExprNoIn ',' AssignmentExprNoIn { $$ = createNodeInfo<ExpressionNode*>(new CommaNode(GLOBAL_DATA, $1.m_node, $3.m_node), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -ExprNoBF: - AssignmentExprNoBF - | ExprNoBF ',' AssignmentExpr { $$ = createNodeInfo<ExpressionNode*>(new CommaNode(GLOBAL_DATA, $1.m_node, $3.m_node), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } -; - -Statement: - Block - | VariableStatement - | ConstStatement - | EmptyStatement - | ExprStatement - | IfStatement - | IterationStatement - | ContinueStatement - | BreakStatement - | ReturnStatement - | WithStatement - | SwitchStatement - | LabelledStatement - | ThrowStatement - | TryStatement - | DebuggerStatement -; - -Block: - OPENBRACE CLOSEBRACE { $$ = createNodeDeclarationInfo<StatementNode*>(new BlockNode(GLOBAL_DATA, 0), 0, 0, 0, 0); - DBG($$.m_node, @1, @2); } - | OPENBRACE SourceElements CLOSEBRACE { $$ = createNodeDeclarationInfo<StatementNode*>(new BlockNode(GLOBAL_DATA, $2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants); - DBG($$.m_node, @1, @3); } -; - -VariableStatement: - VAR VariableDeclarationList ';' { $$ = createNodeDeclarationInfo<StatementNode*>(makeVarStatementNode(GLOBAL_DATA, $2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants); - DBG($$.m_node, @1, @3); } - | VAR VariableDeclarationList error { $$ = createNodeDeclarationInfo<StatementNode*>(makeVarStatementNode(GLOBAL_DATA, $2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants); - DBG($$.m_node, @1, @2); - AUTO_SEMICOLON; } -; - -VariableDeclarationList: - IDENT { $$.m_node = 0; - $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>(GLOBAL_DATA); - appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$1, 0); - $$.m_funcDeclarations = 0; - $$.m_features = (*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0; - $$.m_numConstants = 0; - } - | IDENT Initializer { AssignResolveNode* node = new AssignResolveNode(GLOBAL_DATA, *$1, $2.m_node, $2.m_features & AssignFeature); - SET_EXCEPTION_LOCATION(node, @1.first_column, @2.first_column + 1, @2.last_column); - $$.m_node = node; - $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>(GLOBAL_DATA); - appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$1, DeclarationStacks::HasInitializer); - $$.m_funcDeclarations = 0; - $$.m_features = ((*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $2.m_features; - $$.m_numConstants = $2.m_numConstants; - } - | VariableDeclarationList ',' IDENT - { $$.m_node = $1.m_node; - $$.m_varDeclarations = $1.m_varDeclarations; - appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$3, 0); - $$.m_funcDeclarations = 0; - $$.m_features = $1.m_features | ((*$3 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0); - $$.m_numConstants = $1.m_numConstants; - } - | VariableDeclarationList ',' IDENT Initializer - { AssignResolveNode* node = new AssignResolveNode(GLOBAL_DATA, *$3, $4.m_node, $4.m_features & AssignFeature); - SET_EXCEPTION_LOCATION(node, @3.first_column, @4.first_column + 1, @4.last_column); - $$.m_node = combineVarInitializers(GLOBAL_DATA, $1.m_node, node); - $$.m_varDeclarations = $1.m_varDeclarations; - appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$3, DeclarationStacks::HasInitializer); - $$.m_funcDeclarations = 0; - $$.m_features = $1.m_features | ((*$3 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $4.m_features; - $$.m_numConstants = $1.m_numConstants + $4.m_numConstants; - } -; - -VariableDeclarationListNoIn: - IDENT { $$.m_node = 0; - $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>(GLOBAL_DATA); - appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$1, 0); - $$.m_funcDeclarations = 0; - $$.m_features = (*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0; - $$.m_numConstants = 0; - } - | IDENT InitializerNoIn { AssignResolveNode* node = new AssignResolveNode(GLOBAL_DATA, *$1, $2.m_node, $2.m_features & AssignFeature); - SET_EXCEPTION_LOCATION(node, @1.first_column, @2.first_column + 1, @2.last_column); - $$.m_node = node; - $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>(GLOBAL_DATA); - appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$1, DeclarationStacks::HasInitializer); - $$.m_funcDeclarations = 0; - $$.m_features = ((*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $2.m_features; - $$.m_numConstants = $2.m_numConstants; - } - | VariableDeclarationListNoIn ',' IDENT - { $$.m_node = $1.m_node; - $$.m_varDeclarations = $1.m_varDeclarations; - appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$3, 0); - $$.m_funcDeclarations = 0; - $$.m_features = $1.m_features | ((*$3 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0); - $$.m_numConstants = $1.m_numConstants; - } - | VariableDeclarationListNoIn ',' IDENT InitializerNoIn - { AssignResolveNode* node = new AssignResolveNode(GLOBAL_DATA, *$3, $4.m_node, $4.m_features & AssignFeature); - SET_EXCEPTION_LOCATION(node, @3.first_column, @4.first_column + 1, @4.last_column); - $$.m_node = combineVarInitializers(GLOBAL_DATA, $1.m_node, node); - $$.m_varDeclarations = $1.m_varDeclarations; - appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$3, DeclarationStacks::HasInitializer); - $$.m_funcDeclarations = 0; - $$.m_features = $1.m_features | ((*$3 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $4.m_features; - $$.m_numConstants = $1.m_numConstants + $4.m_numConstants; - } -; - -ConstStatement: - CONSTTOKEN ConstDeclarationList ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new ConstStatementNode(GLOBAL_DATA, $2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants); - DBG($$.m_node, @1, @3); } - | CONSTTOKEN ConstDeclarationList error - { $$ = createNodeDeclarationInfo<StatementNode*>(new ConstStatementNode(GLOBAL_DATA, $2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants); - DBG($$.m_node, @1, @2); AUTO_SEMICOLON; } -; - -ConstDeclarationList: - ConstDeclaration { $$.m_node.head = $1.m_node; - $$.m_node.tail = $$.m_node.head; - $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>(GLOBAL_DATA); - appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, $1.m_node); - $$.m_funcDeclarations = 0; - $$.m_features = $1.m_features; - $$.m_numConstants = $1.m_numConstants; - } - | ConstDeclarationList ',' ConstDeclaration - { $$.m_node.head = $1.m_node.head; - $1.m_node.tail->m_next = $3.m_node; - $$.m_node.tail = $3.m_node; - $$.m_varDeclarations = $1.m_varDeclarations; - appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, $3.m_node); - $$.m_funcDeclarations = 0; - $$.m_features = $1.m_features | $3.m_features; - $$.m_numConstants = $1.m_numConstants + $3.m_numConstants; } -; - -ConstDeclaration: - IDENT { $$ = createNodeInfo<ConstDeclNode*>(new ConstDeclNode(GLOBAL_DATA, *$1, 0), (*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0, 0); } - | IDENT Initializer { $$ = createNodeInfo<ConstDeclNode*>(new ConstDeclNode(GLOBAL_DATA, *$1, $2.m_node), ((*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $2.m_features, $2.m_numConstants); } -; - -Initializer: - '=' AssignmentExpr { $$ = $2; } -; - -InitializerNoIn: - '=' AssignmentExprNoIn { $$ = $2; } -; - -EmptyStatement: - ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new EmptyStatementNode(GLOBAL_DATA), 0, 0, 0, 0); } -; - -ExprStatement: - ExprNoBF ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new ExprStatementNode(GLOBAL_DATA, $1.m_node), 0, 0, $1.m_features, $1.m_numConstants); - DBG($$.m_node, @1, @2); } - | ExprNoBF error { $$ = createNodeDeclarationInfo<StatementNode*>(new ExprStatementNode(GLOBAL_DATA, $1.m_node), 0, 0, $1.m_features, $1.m_numConstants); - DBG($$.m_node, @1, @1); AUTO_SEMICOLON; } -; - -IfStatement: - IF '(' Expr ')' Statement %prec IF_WITHOUT_ELSE - { $$ = createNodeDeclarationInfo<StatementNode*>(new IfNode(GLOBAL_DATA, $3.m_node, $5.m_node), $5.m_varDeclarations, $5.m_funcDeclarations, $3.m_features | $5.m_features, $3.m_numConstants + $5.m_numConstants); - DBG($$.m_node, @1, @4); } - | IF '(' Expr ')' Statement ELSE Statement - { $$ = createNodeDeclarationInfo<StatementNode*>(new IfElseNode(GLOBAL_DATA, $3.m_node, $5.m_node, $7.m_node), - mergeDeclarationLists($5.m_varDeclarations, $7.m_varDeclarations), mergeDeclarationLists($5.m_funcDeclarations, $7.m_funcDeclarations), - $3.m_features | $5.m_features | $7.m_features, - $3.m_numConstants + $5.m_numConstants + $7.m_numConstants); - DBG($$.m_node, @1, @4); } -; - -IterationStatement: - DO Statement WHILE '(' Expr ')' ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new DoWhileNode(GLOBAL_DATA, $2.m_node, $5.m_node), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features | $5.m_features, $2.m_numConstants + $5.m_numConstants); - DBG($$.m_node, @1, @3); } - | DO Statement WHILE '(' Expr ')' error { $$ = createNodeDeclarationInfo<StatementNode*>(new DoWhileNode(GLOBAL_DATA, $2.m_node, $5.m_node), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features | $5.m_features, $2.m_numConstants + $5.m_numConstants); - DBG($$.m_node, @1, @3); } // Always performs automatic semicolon insertion. - | WHILE '(' Expr ')' Statement { $$ = createNodeDeclarationInfo<StatementNode*>(new WhileNode(GLOBAL_DATA, $3.m_node, $5.m_node), $5.m_varDeclarations, $5.m_funcDeclarations, $3.m_features | $5.m_features, $3.m_numConstants + $5.m_numConstants); - DBG($$.m_node, @1, @4); } - | FOR '(' ExprNoInOpt ';' ExprOpt ';' ExprOpt ')' Statement - { $$ = createNodeDeclarationInfo<StatementNode*>(new ForNode(GLOBAL_DATA, $3.m_node, $5.m_node, $7.m_node, $9.m_node, false), $9.m_varDeclarations, $9.m_funcDeclarations, - $3.m_features | $5.m_features | $7.m_features | $9.m_features, - $3.m_numConstants + $5.m_numConstants + $7.m_numConstants + $9.m_numConstants); - DBG($$.m_node, @1, @8); - } - | FOR '(' VAR VariableDeclarationListNoIn ';' ExprOpt ';' ExprOpt ')' Statement - { $$ = createNodeDeclarationInfo<StatementNode*>(new ForNode(GLOBAL_DATA, $4.m_node, $6.m_node, $8.m_node, $10.m_node, true), - mergeDeclarationLists($4.m_varDeclarations, $10.m_varDeclarations), - mergeDeclarationLists($4.m_funcDeclarations, $10.m_funcDeclarations), - $4.m_features | $6.m_features | $8.m_features | $10.m_features, - $4.m_numConstants + $6.m_numConstants + $8.m_numConstants + $10.m_numConstants); - DBG($$.m_node, @1, @9); } - | FOR '(' LeftHandSideExpr INTOKEN Expr ')' Statement - { - ForInNode* node = new ForInNode(GLOBAL_DATA, $3.m_node, $5.m_node, $7.m_node); - SET_EXCEPTION_LOCATION(node, @3.first_column, @3.last_column, @5.last_column); - $$ = createNodeDeclarationInfo<StatementNode*>(node, $7.m_varDeclarations, $7.m_funcDeclarations, - $3.m_features | $5.m_features | $7.m_features, - $3.m_numConstants + $5.m_numConstants + $7.m_numConstants); - DBG($$.m_node, @1, @6); - } - | FOR '(' VAR IDENT INTOKEN Expr ')' Statement - { ForInNode *forIn = new ForInNode(GLOBAL_DATA, *$4, 0, $6.m_node, $8.m_node, @5.first_column, @5.first_column - @4.first_column, @6.last_column - @5.first_column); - SET_EXCEPTION_LOCATION(forIn, @4.first_column, @5.first_column + 1, @6.last_column); - appendToVarDeclarationList(GLOBAL_DATA, $8.m_varDeclarations, *$4, DeclarationStacks::HasInitializer); - $$ = createNodeDeclarationInfo<StatementNode*>(forIn, $8.m_varDeclarations, $8.m_funcDeclarations, ((*$4 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $6.m_features | $8.m_features, $6.m_numConstants + $8.m_numConstants); - DBG($$.m_node, @1, @7); } - | FOR '(' VAR IDENT InitializerNoIn INTOKEN Expr ')' Statement - { ForInNode *forIn = new ForInNode(GLOBAL_DATA, *$4, $5.m_node, $7.m_node, $9.m_node, @5.first_column, @5.first_column - @4.first_column, @5.last_column - @5.first_column); - SET_EXCEPTION_LOCATION(forIn, @4.first_column, @6.first_column + 1, @7.last_column); - appendToVarDeclarationList(GLOBAL_DATA, $9.m_varDeclarations, *$4, DeclarationStacks::HasInitializer); - $$ = createNodeDeclarationInfo<StatementNode*>(forIn, $9.m_varDeclarations, $9.m_funcDeclarations, - ((*$4 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $5.m_features | $7.m_features | $9.m_features, - $5.m_numConstants + $7.m_numConstants + $9.m_numConstants); - DBG($$.m_node, @1, @8); } -; - -ExprOpt: - /* nothing */ { $$ = createNodeInfo<ExpressionNode*>(0, 0, 0); } - | Expr -; - -ExprNoInOpt: - /* nothing */ { $$ = createNodeInfo<ExpressionNode*>(0, 0, 0); } - | ExprNoIn -; - -ContinueStatement: - CONTINUE ';' { ContinueNode* node = new ContinueNode(GLOBAL_DATA); - SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column); - $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); - DBG($$.m_node, @1, @2); } - | CONTINUE error { ContinueNode* node = new ContinueNode(GLOBAL_DATA); - SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column); - $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); - DBG($$.m_node, @1, @1); AUTO_SEMICOLON; } - | CONTINUE IDENT ';' { ContinueNode* node = new ContinueNode(GLOBAL_DATA, *$2); - SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); - $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); - DBG($$.m_node, @1, @3); } - | CONTINUE IDENT error { ContinueNode* node = new ContinueNode(GLOBAL_DATA, *$2); - SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); - $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); - DBG($$.m_node, @1, @2); AUTO_SEMICOLON; } -; - -BreakStatement: - BREAK ';' { BreakNode* node = new BreakNode(GLOBAL_DATA); - SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column); - $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); DBG($$.m_node, @1, @2); } - | BREAK error { BreakNode* node = new BreakNode(GLOBAL_DATA); - SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column); - $$ = createNodeDeclarationInfo<StatementNode*>(new BreakNode(GLOBAL_DATA), 0, 0, 0, 0); DBG($$.m_node, @1, @1); AUTO_SEMICOLON; } - | BREAK IDENT ';' { BreakNode* node = new BreakNode(GLOBAL_DATA, *$2); - SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); - $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); DBG($$.m_node, @1, @3); } - | BREAK IDENT error { BreakNode* node = new BreakNode(GLOBAL_DATA, *$2); - SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); - $$ = createNodeDeclarationInfo<StatementNode*>(new BreakNode(GLOBAL_DATA, *$2), 0, 0, 0, 0); DBG($$.m_node, @1, @2); AUTO_SEMICOLON; } -; - -ReturnStatement: - RETURN ';' { ReturnNode* node = new ReturnNode(GLOBAL_DATA, 0); - SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column); - $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); DBG($$.m_node, @1, @2); } - | RETURN error { ReturnNode* node = new ReturnNode(GLOBAL_DATA, 0); - SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column); - $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); DBG($$.m_node, @1, @1); AUTO_SEMICOLON; } - | RETURN Expr ';' { ReturnNode* node = new ReturnNode(GLOBAL_DATA, $2.m_node); - SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); - $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_features, $2.m_numConstants); DBG($$.m_node, @1, @3); } - | RETURN Expr error { ReturnNode* node = new ReturnNode(GLOBAL_DATA, $2.m_node); - SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); - $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_features, $2.m_numConstants); DBG($$.m_node, @1, @2); AUTO_SEMICOLON; } -; - -WithStatement: - WITH '(' Expr ')' Statement { $$ = createNodeDeclarationInfo<StatementNode*>(new WithNode(GLOBAL_DATA, $3.m_node, $5.m_node, @3.last_column, @3.last_column - @3.first_column), - $5.m_varDeclarations, $5.m_funcDeclarations, $3.m_features | $5.m_features | WithFeature, $3.m_numConstants + $5.m_numConstants); - DBG($$.m_node, @1, @4); } -; - -SwitchStatement: - SWITCH '(' Expr ')' CaseBlock { $$ = createNodeDeclarationInfo<StatementNode*>(new SwitchNode(GLOBAL_DATA, $3.m_node, $5.m_node), $5.m_varDeclarations, $5.m_funcDeclarations, - $3.m_features | $5.m_features, $3.m_numConstants + $5.m_numConstants); - DBG($$.m_node, @1, @4); } -; - -CaseBlock: - OPENBRACE CaseClausesOpt CLOSEBRACE { $$ = createNodeDeclarationInfo<CaseBlockNode*>(new CaseBlockNode(GLOBAL_DATA, $2.m_node.head, 0, 0), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants); } - | OPENBRACE CaseClausesOpt DefaultClause CaseClausesOpt CLOSEBRACE - { $$ = createNodeDeclarationInfo<CaseBlockNode*>(new CaseBlockNode(GLOBAL_DATA, $2.m_node.head, $3.m_node, $4.m_node.head), - mergeDeclarationLists(mergeDeclarationLists($2.m_varDeclarations, $3.m_varDeclarations), $4.m_varDeclarations), - mergeDeclarationLists(mergeDeclarationLists($2.m_funcDeclarations, $3.m_funcDeclarations), $4.m_funcDeclarations), - $2.m_features | $3.m_features | $4.m_features, - $2.m_numConstants + $3.m_numConstants + $4.m_numConstants); } -; - -CaseClausesOpt: -/* nothing */ { $$.m_node.head = 0; $$.m_node.tail = 0; $$.m_varDeclarations = 0; $$.m_funcDeclarations = 0; $$.m_features = 0; $$.m_numConstants = 0; } - | CaseClauses -; - -CaseClauses: - CaseClause { $$.m_node.head = new ClauseListNode(GLOBAL_DATA, $1.m_node); - $$.m_node.tail = $$.m_node.head; - $$.m_varDeclarations = $1.m_varDeclarations; - $$.m_funcDeclarations = $1.m_funcDeclarations; - $$.m_features = $1.m_features; - $$.m_numConstants = $1.m_numConstants; } - | CaseClauses CaseClause { $$.m_node.head = $1.m_node.head; - $$.m_node.tail = new ClauseListNode(GLOBAL_DATA, $1.m_node.tail, $2.m_node); - $$.m_varDeclarations = mergeDeclarationLists($1.m_varDeclarations, $2.m_varDeclarations); - $$.m_funcDeclarations = mergeDeclarationLists($1.m_funcDeclarations, $2.m_funcDeclarations); - $$.m_features = $1.m_features | $2.m_features; - $$.m_numConstants = $1.m_numConstants + $2.m_numConstants; - } -; - -CaseClause: - CASE Expr ':' { $$ = createNodeDeclarationInfo<CaseClauseNode*>(new CaseClauseNode(GLOBAL_DATA, $2.m_node), 0, 0, $2.m_features, $2.m_numConstants); } - | CASE Expr ':' SourceElements { $$ = createNodeDeclarationInfo<CaseClauseNode*>(new CaseClauseNode(GLOBAL_DATA, $2.m_node, $4.m_node), $4.m_varDeclarations, $4.m_funcDeclarations, $2.m_features | $4.m_features, $2.m_numConstants + $4.m_numConstants); } -; - -DefaultClause: - DEFAULT ':' { $$ = createNodeDeclarationInfo<CaseClauseNode*>(new CaseClauseNode(GLOBAL_DATA, 0), 0, 0, 0, 0); } - | DEFAULT ':' SourceElements { $$ = createNodeDeclarationInfo<CaseClauseNode*>(new CaseClauseNode(GLOBAL_DATA, 0, $3.m_node), $3.m_varDeclarations, $3.m_funcDeclarations, $3.m_features, $3.m_numConstants); } -; - -LabelledStatement: - IDENT ':' Statement { LabelNode* node = new LabelNode(GLOBAL_DATA, *$1, $3.m_node); - SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); - $$ = createNodeDeclarationInfo<StatementNode*>(node, $3.m_varDeclarations, $3.m_funcDeclarations, $3.m_features, $3.m_numConstants); } -; - -ThrowStatement: - THROW Expr ';' { ThrowNode* node = new ThrowNode(GLOBAL_DATA, $2.m_node); - SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); - $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_features, $2.m_numConstants); DBG($$.m_node, @1, @2); - } - | THROW Expr error { ThrowNode* node = new ThrowNode(GLOBAL_DATA, $2.m_node); - SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); - $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_features, $2.m_numConstants); DBG($$.m_node, @1, @2); AUTO_SEMICOLON; - } -; - -TryStatement: - TRY Block FINALLY Block { $$ = createNodeDeclarationInfo<StatementNode*>(new TryNode(GLOBAL_DATA, $2.m_node, GLOBAL_DATA->propertyNames->nullIdentifier, 0, $4.m_node), - mergeDeclarationLists($2.m_varDeclarations, $4.m_varDeclarations), - mergeDeclarationLists($2.m_funcDeclarations, $4.m_funcDeclarations), - $2.m_features | $4.m_features, - $2.m_numConstants + $4.m_numConstants); - DBG($$.m_node, @1, @2); } - | TRY Block CATCH '(' IDENT ')' Block { $$ = createNodeDeclarationInfo<StatementNode*>(new TryNode(GLOBAL_DATA, $2.m_node, *$5, $7.m_node, 0), - mergeDeclarationLists($2.m_varDeclarations, $7.m_varDeclarations), - mergeDeclarationLists($2.m_funcDeclarations, $7.m_funcDeclarations), - $2.m_features | $7.m_features | CatchFeature, - $2.m_numConstants + $7.m_numConstants); - DBG($$.m_node, @1, @2); } - | TRY Block CATCH '(' IDENT ')' Block FINALLY Block - { $$ = createNodeDeclarationInfo<StatementNode*>(new TryNode(GLOBAL_DATA, $2.m_node, *$5, $7.m_node, $9.m_node), - mergeDeclarationLists(mergeDeclarationLists($2.m_varDeclarations, $7.m_varDeclarations), $9.m_varDeclarations), - mergeDeclarationLists(mergeDeclarationLists($2.m_funcDeclarations, $7.m_funcDeclarations), $9.m_funcDeclarations), - $2.m_features | $7.m_features | $9.m_features | CatchFeature, - $2.m_numConstants + $7.m_numConstants + $9.m_numConstants); - DBG($$.m_node, @1, @2); } -; - -DebuggerStatement: - DEBUGGER ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new DebuggerStatementNode(GLOBAL_DATA), 0, 0, 0, 0); - DBG($$.m_node, @1, @2); } - | DEBUGGER error { $$ = createNodeDeclarationInfo<StatementNode*>(new DebuggerStatementNode(GLOBAL_DATA), 0, 0, 0, 0); - DBG($$.m_node, @1, @1); AUTO_SEMICOLON; } -; - -FunctionDeclaration: - FUNCTION IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeInfo(new FuncDeclNode(GLOBAL_DATA, *$2, $6, LEXER->sourceCode($5, $7, @5.first_line)), ((*$2 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | ClosureFeature, 0); DBG($6, @5, @7); } - | FUNCTION IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE - { - $$ = createNodeInfo(new FuncDeclNode(GLOBAL_DATA, *$2, $7, LEXER->sourceCode($6, $8, @6.first_line), $4.m_node.head), ((*$2 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $4.m_features | ClosureFeature, 0); - if ($4.m_features & ArgumentsFeature) - $7->setUsesArguments(); - DBG($7, @6, @8); - } -; - -FunctionExpr: - FUNCTION '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeInfo(new FuncExprNode(GLOBAL_DATA, GLOBAL_DATA->propertyNames->nullIdentifier, $5, LEXER->sourceCode($4, $6, @4.first_line)), ClosureFeature, 0); DBG($5, @4, @6); } - | FUNCTION '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE - { - $$ = createNodeInfo(new FuncExprNode(GLOBAL_DATA, GLOBAL_DATA->propertyNames->nullIdentifier, $6, LEXER->sourceCode($5, $7, @5.first_line), $3.m_node.head), $3.m_features | ClosureFeature, 0); - if ($3.m_features & ArgumentsFeature) - $6->setUsesArguments(); - DBG($6, @5, @7); - } - | FUNCTION IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeInfo(new FuncExprNode(GLOBAL_DATA, *$2, $6, LEXER->sourceCode($5, $7, @5.first_line)), ClosureFeature, 0); DBG($6, @5, @7); } - | FUNCTION IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE - { - $$ = createNodeInfo(new FuncExprNode(GLOBAL_DATA, *$2, $7, LEXER->sourceCode($6, $8, @6.first_line), $4.m_node.head), $4.m_features | ClosureFeature, 0); - if ($4.m_features & ArgumentsFeature) - $7->setUsesArguments(); - DBG($7, @6, @8); - } -; - -FormalParameterList: - IDENT { $$.m_node.head = new ParameterNode(GLOBAL_DATA, *$1); - $$.m_features = (*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0; - $$.m_node.tail = $$.m_node.head; } - | FormalParameterList ',' IDENT { $$.m_node.head = $1.m_node.head; - $$.m_features = $1.m_features | ((*$3 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0); - $$.m_node.tail = new ParameterNode(GLOBAL_DATA, $1.m_node.tail, *$3); } -; - -FunctionBody: - /* not in spec */ { $$ = FunctionBodyNode::create(GLOBAL_DATA, 0, 0, 0, NoFeatures, 0); } - | SourceElements { $$ = FunctionBodyNode::create(GLOBAL_DATA, $1.m_node, $1.m_varDeclarations ? &$1.m_varDeclarations->data : 0, - $1.m_funcDeclarations ? &$1.m_funcDeclarations->data : 0, - $1.m_features, $1.m_numConstants); - // As in mergeDeclarationLists() we have to ref/deref to safely get rid of - // the declaration lists. - if ($1.m_varDeclarations) { - $1.m_varDeclarations->ref(); - $1.m_varDeclarations->deref(); - } - if ($1.m_funcDeclarations) { - $1.m_funcDeclarations->ref(); - $1.m_funcDeclarations->deref(); - } - } -; - -Program: - /* not in spec */ { GLOBAL_DATA->parser->didFinishParsing(new SourceElements(GLOBAL_DATA), 0, 0, NoFeatures, @0.last_line, 0); } - | SourceElements { GLOBAL_DATA->parser->didFinishParsing($1.m_node, $1.m_varDeclarations, $1.m_funcDeclarations, $1.m_features, - @1.last_line, $1.m_numConstants); } -; - -SourceElements: - SourceElement { $$.m_node = new SourceElements(GLOBAL_DATA); - $$.m_node->append($1.m_node); - $$.m_varDeclarations = $1.m_varDeclarations; - $$.m_funcDeclarations = $1.m_funcDeclarations; - $$.m_features = $1.m_features; - $$.m_numConstants = $1.m_numConstants; - } - | SourceElements SourceElement { $$.m_node->append($2.m_node); - $$.m_varDeclarations = mergeDeclarationLists($1.m_varDeclarations, $2.m_varDeclarations); - $$.m_funcDeclarations = mergeDeclarationLists($1.m_funcDeclarations, $2.m_funcDeclarations); - $$.m_features = $1.m_features | $2.m_features; - $$.m_numConstants = $1.m_numConstants + $2.m_numConstants; - } -; - -SourceElement: - FunctionDeclaration { $$ = createNodeDeclarationInfo<StatementNode*>($1.m_node, 0, new ParserRefCountedData<DeclarationStacks::FunctionStack>(GLOBAL_DATA), $1.m_features, 0); $$.m_funcDeclarations->data.append($1.m_node); } - | Statement { $$ = $1; } -; - -%% - -static ExpressionNode* makeAssignNode(void* globalPtr, ExpressionNode* loc, Operator op, ExpressionNode* expr, bool locHasAssignments, bool exprHasAssignments, int start, int divot, int end) -{ - if (!loc->isLocation()) - return new AssignErrorNode(GLOBAL_DATA, loc, op, expr, divot, divot - start, end - divot); - - if (loc->isResolveNode()) { - ResolveNode* resolve = static_cast<ResolveNode*>(loc); - if (op == OpEqual) { - AssignResolveNode* node = new AssignResolveNode(GLOBAL_DATA, resolve->identifier(), expr, exprHasAssignments); - SET_EXCEPTION_LOCATION(node, start, divot, end); - return node; - } else - return new ReadModifyResolveNode(GLOBAL_DATA, resolve->identifier(), op, expr, exprHasAssignments, divot, divot - start, end - divot); - } - if (loc->isBracketAccessorNode()) { - BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(loc); - if (op == OpEqual) - return new AssignBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), expr, locHasAssignments, exprHasAssignments, bracket->divot(), bracket->divot() - start, end - bracket->divot()); - else { - ReadModifyBracketNode* node = new ReadModifyBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), op, expr, locHasAssignments, exprHasAssignments, divot, divot - start, end - divot); - node->setSubexpressionInfo(bracket->divot(), bracket->endOffset()); - return node; - } - } - ASSERT(loc->isDotAccessorNode()); - DotAccessorNode* dot = static_cast<DotAccessorNode*>(loc); - if (op == OpEqual) - return new AssignDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), expr, exprHasAssignments, dot->divot(), dot->divot() - start, end - dot->divot()); - - ReadModifyDotNode* node = new ReadModifyDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), op, expr, exprHasAssignments, divot, divot - start, end - divot); - node->setSubexpressionInfo(dot->divot(), dot->endOffset()); - return node; -} - -static ExpressionNode* makePrefixNode(void* globalPtr, ExpressionNode* expr, Operator op, int start, int divot, int end) -{ - if (!expr->isLocation()) - return new PrefixErrorNode(GLOBAL_DATA, expr, op, divot, divot - start, end - divot); - - if (expr->isResolveNode()) { - ResolveNode* resolve = static_cast<ResolveNode*>(expr); - return new PrefixResolveNode(GLOBAL_DATA, resolve->identifier(), op, divot, divot - start, end - divot); - } - if (expr->isBracketAccessorNode()) { - BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr); - PrefixBracketNode* node = new PrefixBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), op, divot, divot - start, end - divot); - node->setSubexpressionInfo(bracket->divot(), bracket->startOffset()); - return node; - } - ASSERT(expr->isDotAccessorNode()); - DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr); - PrefixDotNode* node = new PrefixDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), op, divot, divot - start, end - divot); - node->setSubexpressionInfo(dot->divot(), dot->startOffset()); - return node; -} - -static ExpressionNode* makePostfixNode(void* globalPtr, ExpressionNode* expr, Operator op, int start, int divot, int end) -{ - if (!expr->isLocation()) - return new PostfixErrorNode(GLOBAL_DATA, expr, op, divot, divot - start, end - divot); - - if (expr->isResolveNode()) { - ResolveNode* resolve = static_cast<ResolveNode*>(expr); - return new PostfixResolveNode(GLOBAL_DATA, resolve->identifier(), op, divot, divot - start, end - divot); - } - if (expr->isBracketAccessorNode()) { - BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr); - PostfixBracketNode* node = new PostfixBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), op, divot, divot - start, end - divot); - node->setSubexpressionInfo(bracket->divot(), bracket->endOffset()); - return node; - - } - ASSERT(expr->isDotAccessorNode()); - DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr); - PostfixDotNode* node = new PostfixDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), op, divot, divot - start, end - divot); - node->setSubexpressionInfo(dot->divot(), dot->endOffset()); - return node; -} - -static ExpressionNodeInfo makeFunctionCallNode(void* globalPtr, ExpressionNodeInfo func, ArgumentsNodeInfo args, int start, int divot, int end) -{ - CodeFeatures features = func.m_features | args.m_features; - int numConstants = func.m_numConstants + args.m_numConstants; - if (!func.m_node->isLocation()) - return createNodeInfo<ExpressionNode*>(new FunctionCallValueNode(GLOBAL_DATA, func.m_node, args.m_node, divot, divot - start, end - divot), features, numConstants); - if (func.m_node->isResolveNode()) { - ResolveNode* resolve = static_cast<ResolveNode*>(func.m_node); - const Identifier& identifier = resolve->identifier(); - if (identifier == GLOBAL_DATA->propertyNames->eval) - return createNodeInfo<ExpressionNode*>(new EvalFunctionCallNode(GLOBAL_DATA, args.m_node, divot, divot - start, end - divot), EvalFeature | features, numConstants); - return createNodeInfo<ExpressionNode*>(new FunctionCallResolveNode(GLOBAL_DATA, identifier, args.m_node, divot, divot - start, end - divot), features, numConstants); - } - if (func.m_node->isBracketAccessorNode()) { - BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(func.m_node); - FunctionCallBracketNode* node = new FunctionCallBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), args.m_node, divot, divot - start, end - divot); - node->setSubexpressionInfo(bracket->divot(), bracket->endOffset()); - return createNodeInfo<ExpressionNode*>(node, features, numConstants); - } - ASSERT(func.m_node->isDotAccessorNode()); - DotAccessorNode* dot = static_cast<DotAccessorNode*>(func.m_node); - FunctionCallDotNode* node = new FunctionCallDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), args.m_node, divot, divot - start, end - divot); - node->setSubexpressionInfo(dot->divot(), dot->endOffset()); - return createNodeInfo<ExpressionNode*>(node, features, numConstants); -} - -static ExpressionNode* makeTypeOfNode(void* globalPtr, ExpressionNode* expr) -{ - if (expr->isResolveNode()) { - ResolveNode* resolve = static_cast<ResolveNode*>(expr); - return new TypeOfResolveNode(GLOBAL_DATA, resolve->identifier()); - } - return new TypeOfValueNode(GLOBAL_DATA, expr); -} - -static ExpressionNode* makeDeleteNode(void* globalPtr, ExpressionNode* expr, int start, int divot, int end) -{ - if (!expr->isLocation()) - return new DeleteValueNode(GLOBAL_DATA, expr); - if (expr->isResolveNode()) { - ResolveNode* resolve = static_cast<ResolveNode*>(expr); - return new DeleteResolveNode(GLOBAL_DATA, resolve->identifier(), divot, divot - start, end - divot); - } - if (expr->isBracketAccessorNode()) { - BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr); - return new DeleteBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), divot, divot - start, end - divot); - } - ASSERT(expr->isDotAccessorNode()); - DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr); - return new DeleteDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), divot, divot - start, end - divot); -} - -static PropertyNode* makeGetterOrSetterPropertyNode(void* globalPtr, const Identifier& getOrSet, const Identifier& name, ParameterNode* params, FunctionBodyNode* body, const SourceCode& source) -{ - PropertyNode::Type type; - if (getOrSet == "get") - type = PropertyNode::Getter; - else if (getOrSet == "set") - type = PropertyNode::Setter; - else - return 0; - return new PropertyNode(GLOBAL_DATA, name, new FuncExprNode(GLOBAL_DATA, GLOBAL_DATA->propertyNames->nullIdentifier, body, source, params), type); -} - -static ExpressionNode* makeNegateNode(void* globalPtr, ExpressionNode* n) -{ - if (n->isNumber()) { - NumberNode* number = static_cast<NumberNode*>(n); - - if (number->value() > 0.0) { - number->setValue(-number->value()); - return number; - } - } - - return new NegateNode(GLOBAL_DATA, n); -} - -static NumberNode* makeNumberNode(void* globalPtr, double d) -{ - JSValue* value = JSImmediate::from(d); - if (value) - return new ImmediateNumberNode(GLOBAL_DATA, value, d); - return new NumberNode(GLOBAL_DATA, d); -} - -static ExpressionNode* makeBitwiseNotNode(void* globalPtr, ExpressionNode* expr) -{ - if (expr->isNumber()) - return makeNumberNode(globalPtr, ~toInt32(static_cast<NumberNode*>(expr)->value())); - return new BitwiseNotNode(GLOBAL_DATA, expr); -} - -static ExpressionNode* makeMultNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) -{ - expr1 = expr1->stripUnaryPlus(); - expr2 = expr2->stripUnaryPlus(); - - if (expr1->isNumber() && expr2->isNumber()) - return makeNumberNode(globalPtr, static_cast<NumberNode*>(expr1)->value() * static_cast<NumberNode*>(expr2)->value()); - - if (expr1->isNumber() && static_cast<NumberNode*>(expr1)->value() == 1) - return new UnaryPlusNode(GLOBAL_DATA, expr2); - - if (expr2->isNumber() && static_cast<NumberNode*>(expr2)->value() == 1) - return new UnaryPlusNode(GLOBAL_DATA, expr1); - - return new MultNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments); -} - -static ExpressionNode* makeDivNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) -{ - expr1 = expr1->stripUnaryPlus(); - expr2 = expr2->stripUnaryPlus(); - - if (expr1->isNumber() && expr2->isNumber()) - return makeNumberNode(globalPtr, static_cast<NumberNode*>(expr1)->value() / static_cast<NumberNode*>(expr2)->value()); - return new DivNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments); -} - -static ExpressionNode* makeAddNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) -{ - if (expr1->isNumber() && expr2->isNumber()) - return makeNumberNode(globalPtr, static_cast<NumberNode*>(expr1)->value() + static_cast<NumberNode*>(expr2)->value()); - return new AddNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments); -} - -static ExpressionNode* makeSubNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) -{ - expr1 = expr1->stripUnaryPlus(); - expr2 = expr2->stripUnaryPlus(); - - if (expr1->isNumber() && expr2->isNumber()) - return makeNumberNode(globalPtr, static_cast<NumberNode*>(expr1)->value() - static_cast<NumberNode*>(expr2)->value()); - return new SubNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments); -} - -static ExpressionNode* makeLeftShiftNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) -{ - if (expr1->isNumber() && expr2->isNumber()) - return makeNumberNode(globalPtr, toInt32(static_cast<NumberNode*>(expr1)->value()) << (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f)); - return new LeftShiftNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments); -} - -static ExpressionNode* makeRightShiftNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) -{ - if (expr1->isNumber() && expr2->isNumber()) - return makeNumberNode(globalPtr, toInt32(static_cast<NumberNode*>(expr1)->value()) >> (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f)); - return new RightShiftNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments); -} - -/* called by yyparse on error */ -int yyerror(const char *) -{ - return 1; -} - -/* may we automatically insert a semicolon ? */ -static bool allowAutomaticSemicolon(Lexer& lexer, int yychar) -{ - return yychar == CLOSEBRACE || yychar == 0 || lexer.prevTerminator(); -} - -static ExpressionNode* combineVarInitializers(void* globalPtr, ExpressionNode* list, AssignResolveNode* init) -{ - if (!list) - return init; - return new VarDeclCommaNode(GLOBAL_DATA, list, init); -} - -// We turn variable declarations into either assignments or empty -// statements (which later get stripped out), because the actual -// declaration work is hoisted up to the start of the function body -static StatementNode* makeVarStatementNode(void* globalPtr, ExpressionNode* expr) -{ - if (!expr) - return new EmptyStatementNode(GLOBAL_DATA); - return new VarStatementNode(GLOBAL_DATA, expr); -} - -#undef GLOBAL_DATA diff --git a/JavaScriptCore/kjs/identifier.cpp b/JavaScriptCore/kjs/identifier.cpp deleted file mode 100644 index 50a6cc3..0000000 --- a/JavaScriptCore/kjs/identifier.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "identifier.h" - -#include "ExecState.h" -#include <new> // for placement new -#include <string.h> // for strlen -#include <wtf/Assertions.h> -#include <wtf/FastMalloc.h> -#include <wtf/HashSet.h> - -namespace JSC { - -typedef HashMap<const char*, RefPtr<UString::Rep>, PtrHash<const char*> > LiteralIdentifierTable; - -class IdentifierTable { -public: - ~IdentifierTable() - { - HashSet<UString::Rep*>::iterator end = m_table.end(); - for (HashSet<UString::Rep*>::iterator iter = m_table.begin(); iter != end; ++iter) - (*iter)->setIdentifierTable(0); - } - - std::pair<HashSet<UString::Rep*>::iterator, bool> add(UString::Rep* value) - { - std::pair<HashSet<UString::Rep*>::iterator, bool> result = m_table.add(value); - (*result.first)->setIdentifierTable(this); - return result; - } - - template<typename U, typename V> - std::pair<HashSet<UString::Rep*>::iterator, bool> add(U value) - { - std::pair<HashSet<UString::Rep*>::iterator, bool> result = m_table.add<U, V>(value); - (*result.first)->setIdentifierTable(this); - return result; - } - - void remove(UString::Rep* r) { m_table.remove(r); } - - LiteralIdentifierTable& literalTable() { return m_literalTable; } - -private: - HashSet<UString::Rep*> m_table; - LiteralIdentifierTable m_literalTable; -}; - -IdentifierTable* createIdentifierTable() -{ - return new IdentifierTable; -} - -void deleteIdentifierTable(IdentifierTable* table) -{ - delete table; -} - -bool Identifier::equal(const UString::Rep* r, const char* s) -{ - int length = r->len; - const UChar* d = r->data(); - for (int i = 0; i != length; ++i) - if (d[i] != (unsigned char)s[i]) - return false; - return s[length] == 0; -} - -bool Identifier::equal(const UString::Rep* r, const UChar* s, int length) -{ - if (r->len != length) - return false; - const UChar* d = r->data(); - for (int i = 0; i != length; ++i) - if (d[i] != s[i]) - return false; - return true; -} - -struct CStringTranslator -{ - static unsigned hash(const char* c) - { - return UString::Rep::computeHash(c); - } - - static bool equal(UString::Rep* r, const char* s) - { - return Identifier::equal(r, s); - } - - static void translate(UString::Rep*& location, const char* c, unsigned hash) - { - size_t length = strlen(c); - UChar* d = static_cast<UChar*>(fastMalloc(sizeof(UChar) * length)); - for (size_t i = 0; i != length; i++) - d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend - - UString::Rep* r = UString::Rep::create(d, static_cast<int>(length)).releaseRef(); - r->rc = 0; - r->_hash = hash; - - location = r; - } -}; - -PassRefPtr<UString::Rep> Identifier::add(JSGlobalData* globalData, const char* c) -{ - if (!c) { - UString::Rep::null.hash(); - return &UString::Rep::null; - } - if (!c[0]) { - UString::Rep::empty.hash(); - return &UString::Rep::empty; - } - if (!c[1]) - return add(globalData, globalData->smallStrings.singleCharacterStringRep(static_cast<unsigned char>(c[0]))); - - IdentifierTable& identifierTable = *globalData->identifierTable; - LiteralIdentifierTable& literalIdentifierTable = identifierTable.literalTable(); - - const LiteralIdentifierTable::iterator& iter = literalIdentifierTable.find(c); - if (iter != literalIdentifierTable.end()) - return iter->second; - - UString::Rep* addedString = *identifierTable.add<const char*, CStringTranslator>(c).first; - literalIdentifierTable.add(c, addedString); - - return addedString; -} - -PassRefPtr<UString::Rep> Identifier::add(ExecState* exec, const char* c) -{ - return add(&exec->globalData(), c); -} - -struct UCharBuffer { - const UChar* s; - unsigned int length; -}; - -struct UCharBufferTranslator -{ - static unsigned hash(const UCharBuffer& buf) - { - return UString::Rep::computeHash(buf.s, buf.length); - } - - static bool equal(UString::Rep* str, const UCharBuffer& buf) - { - return Identifier::equal(str, buf.s, buf.length); - } - - static void translate(UString::Rep*& location, const UCharBuffer& buf, unsigned hash) - { - UChar* d = static_cast<UChar*>(fastMalloc(sizeof(UChar) * buf.length)); - for (unsigned i = 0; i != buf.length; i++) - d[i] = buf.s[i]; - - UString::Rep* r = UString::Rep::create(d, buf.length).releaseRef(); - r->rc = 0; - r->_hash = hash; - - location = r; - } -}; - -PassRefPtr<UString::Rep> Identifier::add(JSGlobalData* globalData, const UChar* s, int length) -{ - if (length == 1) { - UChar c = s[0]; - if (c <= 0xFF) - return add(globalData, globalData->smallStrings.singleCharacterStringRep(c)); - } - if (!length) { - UString::Rep::empty.hash(); - return &UString::Rep::empty; - } - UCharBuffer buf = {s, length}; - return *globalData->identifierTable->add<UCharBuffer, UCharBufferTranslator>(buf).first; -} - -PassRefPtr<UString::Rep> Identifier::add(ExecState* exec, const UChar* s, int length) -{ - return add(&exec->globalData(), s, length); -} - -PassRefPtr<UString::Rep> Identifier::addSlowCase(JSGlobalData* globalData, UString::Rep* r) -{ - ASSERT(!r->identifierTable()); - if (r->len == 1) { - UChar c = r->data()[0]; - if (c <= 0xFF) - r = globalData->smallStrings.singleCharacterStringRep(c); - if (r->identifierTable()) { -#ifndef NDEBUG - checkSameIdentifierTable(globalData, r); -#endif - return r; - } - } - if (!r->len) { - UString::Rep::empty.hash(); - return &UString::Rep::empty; - } - return *globalData->identifierTable->add(r).first; -} - -PassRefPtr<UString::Rep> Identifier::addSlowCase(ExecState* exec, UString::Rep* r) -{ - return addSlowCase(&exec->globalData(), r); -} - -void Identifier::remove(UString::Rep* r) -{ - r->identifierTable()->remove(r); -} - -#ifndef NDEBUG - -void Identifier::checkSameIdentifierTable(ExecState* exec, UString::Rep* rep) -{ - ASSERT(rep->identifierTable() == exec->globalData().identifierTable); -} - -void Identifier::checkSameIdentifierTable(JSGlobalData* globalData, UString::Rep* rep) -{ - ASSERT(rep->identifierTable() == globalData->identifierTable); -} - -#else - -void Identifier::checkSameIdentifierTable(ExecState*, UString::Rep*) -{ -} - -void Identifier::checkSameIdentifierTable(JSGlobalData*, UString::Rep*) -{ -} - -#endif - -} // namespace JSC diff --git a/JavaScriptCore/kjs/identifier.h b/JavaScriptCore/kjs/identifier.h deleted file mode 100644 index a79dd92..0000000 --- a/JavaScriptCore/kjs/identifier.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#ifndef KJS_IDENTIFIER_H -#define KJS_IDENTIFIER_H - -#include "JSGlobalData.h" -#include "ustring.h" - -namespace JSC { - - class ExecState; - - class Identifier { - friend class StructureID; - public: - Identifier() { } - - Identifier(ExecState* exec, const char* s) : _ustring(add(exec, s)) { } // Only to be used with string literals. - Identifier(ExecState* exec, const UChar* s, int length) : _ustring(add(exec, s, length)) { } - Identifier(ExecState* exec, UString::Rep* rep) : _ustring(add(exec, rep)) { } - Identifier(ExecState* exec, const UString& s) : _ustring(add(exec, s.rep())) { } - - Identifier(JSGlobalData* globalData, const char* s) : _ustring(add(globalData, s)) { } // Only to be used with string literals. - Identifier(JSGlobalData* globalData, const UChar* s, int length) : _ustring(add(globalData, s, length)) { } - Identifier(JSGlobalData* globalData, UString::Rep* rep) : _ustring(add(globalData, rep)) { } - Identifier(JSGlobalData* globalData, const UString& s) : _ustring(add(globalData, s.rep())) { } - - // Special constructor for cases where we overwrite an object in place. - Identifier(PlacementNewAdoptType) : _ustring(PlacementNewAdopt) { } - - const UString& ustring() const { return _ustring; } - - const UChar* data() const { return _ustring.data(); } - int size() const { return _ustring.size(); } - - const char* ascii() const { return _ustring.ascii(); } - - static Identifier from(ExecState* exec, unsigned y) { return Identifier(exec, UString::from(y)); } - - bool isNull() const { return _ustring.isNull(); } - bool isEmpty() const { return _ustring.isEmpty(); } - - uint32_t toUInt32(bool* ok) const { return _ustring.toUInt32(ok); } - uint32_t toUInt32(bool* ok, bool tolerateEmptyString) const { return _ustring.toUInt32(ok, tolerateEmptyString); }; - uint32_t toStrictUInt32(bool* ok) const { return _ustring.toStrictUInt32(ok); } - unsigned toArrayIndex(bool* ok) const { return _ustring.toArrayIndex(ok); } - double toDouble() const { return _ustring.toDouble(); } - - friend bool operator==(const Identifier&, const Identifier&); - friend bool operator!=(const Identifier&, const Identifier&); - - friend bool operator==(const Identifier&, const char*); - - static void remove(UString::Rep*); - - static bool equal(const UString::Rep*, const char*); - static bool equal(const UString::Rep*, const UChar*, int length); - static bool equal(const UString::Rep* a, const UString::Rep* b) { return JSC::equal(a, b); } - - static PassRefPtr<UString::Rep> add(ExecState*, const char*); // Only to be used with string literals. - static PassRefPtr<UString::Rep> add(JSGlobalData*, const char*); // Only to be used with string literals. - - static void initializeIdentifierThreading(); - - private: - UString _ustring; - - static bool equal(const Identifier& a, const Identifier& b) { return a._ustring.rep() == b._ustring.rep(); } - static bool equal(const Identifier& a, const char* b) { return equal(a._ustring.rep(), b); } - - static PassRefPtr<UString::Rep> add(ExecState*, const UChar*, int length); - static PassRefPtr<UString::Rep> add(JSGlobalData*, const UChar*, int length); - - static PassRefPtr<UString::Rep> add(ExecState* exec, UString::Rep* r) - { - if (r->identifierTable()) { -#ifndef NDEBUG - checkSameIdentifierTable(exec, r); -#endif - return r; - } - return addSlowCase(exec, r); - } - static PassRefPtr<UString::Rep> add(JSGlobalData* globalData, UString::Rep* r) - { - if (r->identifierTable()) { -#ifndef NDEBUG - checkSameIdentifierTable(globalData, r); -#endif - return r; - } - return addSlowCase(globalData, r); - } - - static PassRefPtr<UString::Rep> addSlowCase(ExecState*, UString::Rep* r); - static PassRefPtr<UString::Rep> addSlowCase(JSGlobalData*, UString::Rep* r); - - static void checkSameIdentifierTable(ExecState*, UString::Rep*); - static void checkSameIdentifierTable(JSGlobalData*, UString::Rep*); - }; - - inline bool operator==(const Identifier& a, const Identifier& b) - { - return Identifier::equal(a, b); - } - - inline bool operator!=(const Identifier& a, const Identifier& b) - { - return !Identifier::equal(a, b); - } - - inline bool operator==(const Identifier& a, const char* b) - { - return Identifier::equal(a, b); - } - - IdentifierTable* createIdentifierTable(); - void deleteIdentifierTable(IdentifierTable*); - -} // namespace JSC - -#endif // KJS_IDENTIFIER_H diff --git a/JavaScriptCore/kjs/interpreter.cpp b/JavaScriptCore/kjs/interpreter.cpp deleted file mode 100644 index 1188349..0000000 --- a/JavaScriptCore/kjs/interpreter.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) - * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2007 Apple Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "interpreter.h" - -#include "ExecState.h" -#include "JSGlobalObject.h" -#include "JSLock.h" -#include "Machine.h" -#include "Parser.h" -#include "completion.h" -#include "Debugger.h" -#include <stdio.h> - -#if !PLATFORM(WIN_OS) -#include <unistd.h> -#endif - -namespace JSC { - -Completion Interpreter::checkSyntax(ExecState* exec, const SourceCode& source) -{ - JSLock lock(exec); - - int errLine; - UString errMsg; - - RefPtr<ProgramNode> progNode = exec->globalData().parser->parse<ProgramNode>(exec, exec->dynamicGlobalObject()->debugger(), source, &errLine, &errMsg); - if (!progNode) - return Completion(Throw, Error::create(exec, SyntaxError, errMsg, errLine, source.provider()->asID(), source.provider()->url())); - return Completion(Normal); -} - -Completion Interpreter::evaluate(ExecState* exec, ScopeChain& scopeChain, const SourceCode& source, JSValue* thisValue) -{ - JSLock lock(exec); - - int errLine; - UString errMsg; - RefPtr<ProgramNode> programNode = exec->globalData().parser->parse<ProgramNode>(exec, exec->dynamicGlobalObject()->debugger(), source, &errLine, &errMsg); - - if (!programNode) - return Completion(Throw, Error::create(exec, SyntaxError, errMsg, errLine, source.provider()->asID(), source.provider()->url())); - - JSObject* thisObj = (!thisValue || thisValue->isUndefinedOrNull()) ? exec->dynamicGlobalObject() : thisValue->toObject(exec); - - JSValue* exception = noValue(); - JSValue* result = exec->machine()->execute(programNode.get(), exec, scopeChain.node(), thisObj, &exception); - - if (exception) { - if (exception->isObject() && asObject(exception)->isWatchdogException()) - return Completion(Interrupted, result); - return Completion(Throw, exception); - } - return Completion(Normal, result); -} - -} // namespace JSC diff --git a/JavaScriptCore/kjs/interpreter.h b/JavaScriptCore/kjs/interpreter.h deleted file mode 100644 index 0366063..0000000 --- a/JavaScriptCore/kjs/interpreter.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) - * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2007 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#ifndef KJS_Interpreter_h -#define KJS_Interpreter_h - -#include "JSValue.h" -#include <wtf/PassRefPtr.h> -#include <wtf/unicode/Unicode.h> - -namespace JSC { - - class Completion; - class ExecState; - class ScopeChain; - class SourceCode; - - class Interpreter { - public: - /** - * Parses the supplied ECMAScript code and checks for syntax errors. - * - * @param code The code to check - * @return A normal completion if there were no syntax errors in the code, - * otherwise a throw completion with the syntax error as its value. - */ - static Completion checkSyntax(ExecState*, const SourceCode&); - - /** - * Evaluates the supplied ECMAScript code. - * - * Since this method returns a Completion, you should check the type of - * completion to detect an error or before attempting to access the returned - * value. For example, if an error occurs during script execution and is not - * caught by the script, the completion type will be Throw. - * - * If the supplied code is invalid, a SyntaxError will be thrown. - * - * @param code The code to evaluate - * @param thisValue The value to pass in as the "this" value for the script - * execution. This should either be jsNull() or an Object. - * @return A completion object representing the result of the execution. - */ - static Completion evaluate(ExecState*, ScopeChain&, const SourceCode&, JSValue* thisValue = noValue()); - }; - -} // namespace JSC - -#endif // KJS_Interpreter_h diff --git a/JavaScriptCore/kjs/jsc.pro b/JavaScriptCore/kjs/jsc.pro deleted file mode 100644 index 2a30d65..0000000 --- a/JavaScriptCore/kjs/jsc.pro +++ /dev/null @@ -1,35 +0,0 @@ -TEMPLATE = app -TARGET = jsc -DESTDIR = .. -SOURCES = Shell.cpp -QT -= gui -INCLUDEPATH += $$PWD/.. \ - $$PWD \ - $$PWD/../bindings \ - $$PWD/../bindings/c \ - $$PWD/../wtf \ - $$PWD/../VM -CONFIG -= app_bundle -DEFINES += BUILDING_QT__ -CONFIG += building-libs - -CONFIG(release) { - DEFINES += NDEBUG USE_SYSTEM_MALLOC -} - -include($$PWD/../../WebKit.pri) - -CONFIG += link_pkgconfig - -QMAKE_RPATHDIR += $$OUTPUT_DIR/lib - -isEmpty(OUTPUT_DIR):OUTPUT_DIR=$$PWD/../.. -include($$OUTPUT_DIR/config.pri) -OBJECTS_DIR = tmp -OBJECTS_DIR_WTR = $$OBJECTS_DIR/ -win32-*: OBJECTS_DIR_WTR ~= s|/|\| -include($$PWD/../JavaScriptCore.pri) - -lessThan(QT_MINOR_VERSION, 4) { - DEFINES += QT_BEGIN_NAMESPACE="" QT_END_NAMESPACE="" -} diff --git a/JavaScriptCore/kjs/keywords.table b/JavaScriptCore/kjs/keywords.table deleted file mode 100644 index 490c1cc..0000000 --- a/JavaScriptCore/kjs/keywords.table +++ /dev/null @@ -1,72 +0,0 @@ -# main keywords -@begin mainTable 41 - -# types -null NULLTOKEN -true TRUETOKEN -false FALSETOKEN - -# keywords -break BREAK -case CASE -catch CATCH -const CONSTTOKEN -default DEFAULT -finally FINALLY -for FOR -instanceof INSTANCEOF -new NEW -var VAR -continue CONTINUE -function FUNCTION -return RETURN -void VOIDTOKEN -delete DELETETOKEN -if IF -this THISTOKEN -do DO -while WHILE -else ELSE -in INTOKEN -switch SWITCH -throw THROW -try TRY -typeof TYPEOF -with WITH -debugger DEBUGGER - -# reserved for future use -class RESERVED -enum RESERVED -export RESERVED -extends RESERVED -import RESERVED -super RESERVED - -# these words are reserved for future use in the ECMA spec, but not in WinIE -# (see http://bugs.webkit.org/show_bug.cgi?id=6179) -# abstract RESERVED -# boolean RESERVED -# byte RESERVED -# char RESERVED -# double RESERVED -# final RESERVED -# float RESERVED -# goto RESERVED -# implements RESERVED -# int RESERVED -# interface RESERVED -# long RESERVED -# native RESERVED -# package RESERVED -# private RESERVED -# protected RESERVED -# public RESERVED -# short RESERVED -# static RESERVED -# synchronized RESERVED -# throws RESERVED -# transient RESERVED -# volatile RESERVED -@end - diff --git a/JavaScriptCore/kjs/lexer.cpp b/JavaScriptCore/kjs/lexer.cpp deleted file mode 100644 index 7313b12..0000000 --- a/JavaScriptCore/kjs/lexer.cpp +++ /dev/null @@ -1,920 +0,0 @@ -/* - * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2006, 2007, 2008 Apple Inc. All Rights Reserved. - * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "lexer.h" - -#include "dtoa.h" -#include "JSFunction.h" -#include "nodes.h" -#include "NodeInfo.h" -#include "JSGlobalObjectFunctions.h" -#include <ctype.h> -#include <limits.h> -#include <string.h> -#include <wtf/Assertions.h> -#include <wtf/unicode/Unicode.h> - -using namespace WTF; -using namespace Unicode; - -// we can't specify the namespace in yacc's C output, so do it here -using namespace JSC; - -#ifndef KDE_USE_FINAL -#include "grammar.h" -#endif - -#include "lookup.h" -#include "lexer.lut.h" - -// a bridge for yacc from the C world to C++ -int kjsyylex(void* lvalp, void* llocp, void* globalData) -{ - return static_cast<JSGlobalData*>(globalData)->lexer->lex(lvalp, llocp); -} - -namespace JSC { - -static bool isDecimalDigit(int); - -static const size_t initialReadBufferCapacity = 32; -static const size_t initialStringTableCapacity = 64; - -Lexer::Lexer(JSGlobalData* globalData) - : yylineno(1) - , m_restrKeyword(false) - , m_eatNextIdentifier(false) - , m_stackToken(-1) - , m_lastToken(-1) - , m_position(0) - , m_code(0) - , m_length(0) - , m_atLineStart(true) - , m_current(0) - , m_next1(0) - , m_next2(0) - , m_next3(0) - , m_currentOffset(0) - , m_nextOffset1(0) - , m_nextOffset2(0) - , m_nextOffset3(0) - , m_globalData(globalData) - , m_mainTable(JSC::mainTable) -{ - m_buffer8.reserveCapacity(initialReadBufferCapacity); - m_buffer16.reserveCapacity(initialReadBufferCapacity); - m_strings.reserveCapacity(initialStringTableCapacity); - m_identifiers.reserveCapacity(initialStringTableCapacity); -} - -Lexer::~Lexer() -{ - m_mainTable.deleteTable(); -} - -void Lexer::setCode(const SourceCode& source) -{ - yylineno = source.firstLine(); - m_restrKeyword = false; - m_delimited = false; - m_eatNextIdentifier = false; - m_stackToken = -1; - m_lastToken = -1; - - m_position = 0; - m_source = &source; - m_code = source.data(); - m_length = source.length(); - m_skipLF = false; - m_skipCR = false; - m_error = false; - m_atLineStart = true; - - // read first characters - shift(4); -} - -void Lexer::shift(unsigned p) -{ - // ECMA-262 calls for stripping Cf characters here, but we only do this for BOM, - // see <https://bugs.webkit.org/show_bug.cgi?id=4931>. - - while (p--) { - m_current = m_next1; - m_next1 = m_next2; - m_next2 = m_next3; - m_currentOffset = m_nextOffset1; - m_nextOffset1 = m_nextOffset2; - m_nextOffset2 = m_nextOffset3; - do { - if (m_position >= m_length) { - m_nextOffset3 = m_position; - m_position++; - m_next3 = -1; - break; - } - m_nextOffset3 = m_position; - m_next3 = m_code[m_position++]; - } while (m_next3 == 0xFEFF); - } -} - -// called on each new line -void Lexer::nextLine() -{ - yylineno++; - m_atLineStart = true; -} - -void Lexer::setDone(State s) -{ - m_state = s; - m_done = true; -} - -int Lexer::lex(void* p1, void* p2) -{ - YYSTYPE* lvalp = static_cast<YYSTYPE*>(p1); - YYLTYPE* llocp = static_cast<YYLTYPE*>(p2); - int token = 0; - m_state = Start; - unsigned short stringType = 0; // either single or double quotes - m_buffer8.clear(); - m_buffer16.clear(); - m_done = false; - m_terminator = false; - m_skipLF = false; - m_skipCR = false; - - // did we push a token on the stack previously ? - // (after an automatic semicolon insertion) - if (m_stackToken >= 0) { - setDone(Other); - token = m_stackToken; - m_stackToken = 0; - } - int startOffset = m_currentOffset; - while (!m_done) { - if (m_skipLF && m_current != '\n') // found \r but not \n afterwards - m_skipLF = false; - if (m_skipCR && m_current != '\r') // found \n but not \r afterwards - m_skipCR = false; - if (m_skipLF || m_skipCR) { // found \r\n or \n\r -> eat the second one - m_skipLF = false; - m_skipCR = false; - shift(1); - } - switch (m_state) { - case Start: - startOffset = m_currentOffset; - if (isWhiteSpace()) { - // do nothing - } else if (m_current == '/' && m_next1 == '/') { - shift(1); - m_state = InSingleLineComment; - } else if (m_current == '/' && m_next1 == '*') { - shift(1); - m_state = InMultiLineComment; - } else if (m_current == -1) { - if (!m_terminator && !m_delimited) { - // automatic semicolon insertion if program incomplete - token = ';'; - m_stackToken = 0; - setDone(Other); - } else - setDone(Eof); - } else if (isLineTerminator()) { - nextLine(); - m_terminator = true; - if (m_restrKeyword) { - token = ';'; - setDone(Other); - } - } else if (m_current == '"' || m_current == '\'') { - m_state = InString; - stringType = static_cast<unsigned short>(m_current); - } else if (isIdentStart(m_current)) { - record16(m_current); - m_state = InIdentifierOrKeyword; - } else if (m_current == '\\') - m_state = InIdentifierStartUnicodeEscapeStart; - else if (m_current == '0') { - record8(m_current); - m_state = InNum0; - } else if (isDecimalDigit(m_current)) { - record8(m_current); - m_state = InNum; - } else if (m_current == '.' && isDecimalDigit(m_next1)) { - record8(m_current); - m_state = InDecimal; - // <!-- marks the beginning of a line comment (for www usage) - } else if (m_current == '<' && m_next1 == '!' && m_next2 == '-' && m_next3 == '-') { - shift(3); - m_state = InSingleLineComment; - // same for --> - } else if (m_atLineStart && m_current == '-' && m_next1 == '-' && m_next2 == '>') { - shift(2); - m_state = InSingleLineComment; - } else { - token = matchPunctuator(lvalp->intValue, m_current, m_next1, m_next2, m_next3); - if (token != -1) - setDone(Other); - else - setDone(Bad); - } - break; - case InString: - if (m_current == stringType) { - shift(1); - setDone(String); - } else if (isLineTerminator() || m_current == -1) - setDone(Bad); - else if (m_current == '\\') - m_state = InEscapeSequence; - else - record16(m_current); - break; - // Escape Sequences inside of strings - case InEscapeSequence: - if (isOctalDigit(m_current)) { - if (m_current >= '0' && m_current <= '3' && - isOctalDigit(m_next1) && isOctalDigit(m_next2)) { - record16(convertOctal(m_current, m_next1, m_next2)); - shift(2); - m_state = InString; - } else if (isOctalDigit(m_current) && isOctalDigit(m_next1)) { - record16(convertOctal('0', m_current, m_next1)); - shift(1); - m_state = InString; - } else if (isOctalDigit(m_current)) { - record16(convertOctal('0', '0', m_current)); - m_state = InString; - } else - setDone(Bad); - } else if (m_current == 'x') - m_state = InHexEscape; - else if (m_current == 'u') - m_state = InUnicodeEscape; - else if (isLineTerminator()) { - nextLine(); - m_state = InString; - } else { - record16(singleEscape(static_cast<unsigned short>(m_current))); - m_state = InString; - } - break; - case InHexEscape: - if (isHexDigit(m_current) && isHexDigit(m_next1)) { - m_state = InString; - record16(convertHex(m_current, m_next1)); - shift(1); - } else if (m_current == stringType) { - record16('x'); - shift(1); - setDone(String); - } else { - record16('x'); - record16(m_current); - m_state = InString; - } - break; - case InUnicodeEscape: - if (isHexDigit(m_current) && isHexDigit(m_next1) && isHexDigit(m_next2) && isHexDigit(m_next3)) { - record16(convertUnicode(m_current, m_next1, m_next2, m_next3)); - shift(3); - m_state = InString; - } else if (m_current == stringType) { - record16('u'); - shift(1); - setDone(String); - } else - setDone(Bad); - break; - case InSingleLineComment: - if (isLineTerminator()) { - nextLine(); - m_terminator = true; - if (m_restrKeyword) { - token = ';'; - setDone(Other); - } else - m_state = Start; - } else if (m_current == -1) - setDone(Eof); - break; - case InMultiLineComment: - if (m_current == -1) - setDone(Bad); - else if (isLineTerminator()) - nextLine(); - else if (m_current == '*' && m_next1 == '/') { - m_state = Start; - shift(1); - } - break; - case InIdentifierOrKeyword: - case InIdentifier: - if (isIdentPart(m_current)) - record16(m_current); - else if (m_current == '\\') - m_state = InIdentifierPartUnicodeEscapeStart; - else - setDone(m_state == InIdentifierOrKeyword ? IdentifierOrKeyword : Identifier); - break; - case InNum0: - if (m_current == 'x' || m_current == 'X') { - record8(m_current); - m_state = InHex; - } else if (m_current == '.') { - record8(m_current); - m_state = InDecimal; - } else if (m_current == 'e' || m_current == 'E') { - record8(m_current); - m_state = InExponentIndicator; - } else if (isOctalDigit(m_current)) { - record8(m_current); - m_state = InOctal; - } else if (isDecimalDigit(m_current)) { - record8(m_current); - m_state = InDecimal; - } else - setDone(Number); - break; - case InHex: - if (isHexDigit(m_current)) - record8(m_current); - else - setDone(Hex); - break; - case InOctal: - if (isOctalDigit(m_current)) - record8(m_current); - else if (isDecimalDigit(m_current)) { - record8(m_current); - m_state = InDecimal; - } else - setDone(Octal); - break; - case InNum: - if (isDecimalDigit(m_current)) - record8(m_current); - else if (m_current == '.') { - record8(m_current); - m_state = InDecimal; - } else if (m_current == 'e' || m_current == 'E') { - record8(m_current); - m_state = InExponentIndicator; - } else - setDone(Number); - break; - case InDecimal: - if (isDecimalDigit(m_current)) - record8(m_current); - else if (m_current == 'e' || m_current == 'E') { - record8(m_current); - m_state = InExponentIndicator; - } else - setDone(Number); - break; - case InExponentIndicator: - if (m_current == '+' || m_current == '-') - record8(m_current); - else if (isDecimalDigit(m_current)) { - record8(m_current); - m_state = InExponent; - } else - setDone(Bad); - break; - case InExponent: - if (isDecimalDigit(m_current)) - record8(m_current); - else - setDone(Number); - break; - case InIdentifierStartUnicodeEscapeStart: - if (m_current == 'u') - m_state = InIdentifierStartUnicodeEscape; - else - setDone(Bad); - break; - case InIdentifierPartUnicodeEscapeStart: - if (m_current == 'u') - m_state = InIdentifierPartUnicodeEscape; - else - setDone(Bad); - break; - case InIdentifierStartUnicodeEscape: - if (!isHexDigit(m_current) || !isHexDigit(m_next1) || !isHexDigit(m_next2) || !isHexDigit(m_next3)) { - setDone(Bad); - break; - } - token = convertUnicode(m_current, m_next1, m_next2, m_next3); - shift(3); - if (!isIdentStart(token)) { - setDone(Bad); - break; - } - record16(token); - m_state = InIdentifier; - break; - case InIdentifierPartUnicodeEscape: - if (!isHexDigit(m_current) || !isHexDigit(m_next1) || !isHexDigit(m_next2) || !isHexDigit(m_next3)) { - setDone(Bad); - break; - } - token = convertUnicode(m_current, m_next1, m_next2, m_next3); - shift(3); - if (!isIdentPart(token)) { - setDone(Bad); - break; - } - record16(token); - m_state = InIdentifier; - break; - default: - ASSERT(!"Unhandled state in switch statement"); - } - - // move on to the next character - if (!m_done) - shift(1); - if (m_state != Start && m_state != InSingleLineComment) - m_atLineStart = false; - } - - // no identifiers allowed directly after numeric literal, e.g. "3in" is bad - if ((m_state == Number || m_state == Octal || m_state == Hex) && isIdentStart(m_current)) - m_state = Bad; - - // terminate string - m_buffer8.append('\0'); - -#ifdef KJS_DEBUG_LEX - fprintf(stderr, "line: %d ", lineNo()); - fprintf(stderr, "yytext (%x): ", m_buffer8[0]); - fprintf(stderr, "%s ", m_buffer8.data()); -#endif - - double dval = 0; - if (m_state == Number) - dval = strtod(m_buffer8.data(), 0L); - else if (m_state == Hex) { // scan hex numbers - const char* p = m_buffer8.data() + 2; - while (char c = *p++) { - dval *= 16; - dval += convertHex(c); - } - - if (dval >= mantissaOverflowLowerBound) - dval = parseIntOverflow(m_buffer8.data() + 2, p - (m_buffer8.data() + 3), 16); - - m_state = Number; - } else if (m_state == Octal) { // scan octal number - const char* p = m_buffer8.data() + 1; - while (char c = *p++) { - dval *= 8; - dval += c - '0'; - } - - if (dval >= mantissaOverflowLowerBound) - dval = parseIntOverflow(m_buffer8.data() + 1, p - (m_buffer8.data() + 2), 8); - - m_state = Number; - } - -#ifdef KJS_DEBUG_LEX - switch (m_state) { - case Eof: - printf("(EOF)\n"); - break; - case Other: - printf("(Other)\n"); - break; - case Identifier: - printf("(Identifier)/(Keyword)\n"); - break; - case String: - printf("(String)\n"); - break; - case Number: - printf("(Number)\n"); - break; - default: - printf("(unknown)"); - } -#endif - - if (m_state != Identifier) - m_eatNextIdentifier = false; - - m_restrKeyword = false; - m_delimited = false; - llocp->first_line = yylineno; - llocp->last_line = yylineno; - llocp->first_column = startOffset; - llocp->last_column = m_currentOffset; - switch (m_state) { - case Eof: - token = 0; - break; - case Other: - if (token == '}' || token == ';') - m_delimited = true; - break; - case Identifier: - // Apply anonymous-function hack below (eat the identifier). - if (m_eatNextIdentifier) { - m_eatNextIdentifier = false; - token = lex(lvalp, llocp); - break; - } - lvalp->ident = makeIdentifier(m_buffer16); - token = IDENT; - break; - case IdentifierOrKeyword: { - lvalp->ident = makeIdentifier(m_buffer16); - const HashEntry* entry = m_mainTable.entry(m_globalData, *lvalp->ident); - if (!entry) { - // Lookup for keyword failed, means this is an identifier. - token = IDENT; - break; - } - token = entry->lexerValue(); - // Hack for "f = function somename() { ... }"; too hard to get into the grammar. - m_eatNextIdentifier = token == FUNCTION && m_lastToken == '='; - if (token == CONTINUE || token == BREAK || token == RETURN || token == THROW) - m_restrKeyword = true; - break; - } - case String: - // Atomize constant strings in case they're later used in property lookup. - lvalp->ident = makeIdentifier(m_buffer16); - token = STRING; - break; - case Number: - lvalp->doubleValue = dval; - token = NUMBER; - break; - case Bad: -#ifdef KJS_DEBUG_LEX - fprintf(stderr, "yylex: ERROR.\n"); -#endif - m_error = true; - return -1; - default: - ASSERT(!"unhandled numeration value in switch"); - m_error = true; - return -1; - } - m_lastToken = token; - return token; -} - -bool Lexer::isWhiteSpace() const -{ - return m_current == '\t' || m_current == 0x0b || m_current == 0x0c || isSeparatorSpace(m_current); -} - -bool Lexer::isLineTerminator() -{ - bool cr = (m_current == '\r'); - bool lf = (m_current == '\n'); - if (cr) - m_skipLF = true; - else if (lf) - m_skipCR = true; - return cr || lf || m_current == 0x2028 || m_current == 0x2029; -} - -bool Lexer::isIdentStart(int c) -{ - return (category(c) & (Letter_Uppercase | Letter_Lowercase | Letter_Titlecase | Letter_Modifier | Letter_Other)) - || c == '$' || c == '_'; -} - -bool Lexer::isIdentPart(int c) -{ - return (category(c) & (Letter_Uppercase | Letter_Lowercase | Letter_Titlecase | Letter_Modifier | Letter_Other - | Mark_NonSpacing | Mark_SpacingCombining | Number_DecimalDigit | Punctuation_Connector)) - || c == '$' || c == '_'; -} - -static bool isDecimalDigit(int c) -{ - return (c >= '0' && c <= '9'); -} - -bool Lexer::isHexDigit(int c) -{ - return (c >= '0' && c <= '9' - || c >= 'a' && c <= 'f' - || c >= 'A' && c <= 'F'); -} - -bool Lexer::isOctalDigit(int c) -{ - return (c >= '0' && c <= '7'); -} - -int Lexer::matchPunctuator(int& charPos, int c1, int c2, int c3, int c4) -{ - if (c1 == '>' && c2 == '>' && c3 == '>' && c4 == '=') { - shift(4); - return URSHIFTEQUAL; - } - if (c1 == '=' && c2 == '=' && c3 == '=') { - shift(3); - return STREQ; - } - if (c1 == '!' && c2 == '=' && c3 == '=') { - shift(3); - return STRNEQ; - } - if (c1 == '>' && c2 == '>' && c3 == '>') { - shift(3); - return URSHIFT; - } - if (c1 == '<' && c2 == '<' && c3 == '=') { - shift(3); - return LSHIFTEQUAL; - } - if (c1 == '>' && c2 == '>' && c3 == '=') { - shift(3); - return RSHIFTEQUAL; - } - if (c1 == '<' && c2 == '=') { - shift(2); - return LE; - } - if (c1 == '>' && c2 == '=') { - shift(2); - return GE; - } - if (c1 == '!' && c2 == '=') { - shift(2); - return NE; - } - if (c1 == '+' && c2 == '+') { - shift(2); - if (m_terminator) - return AUTOPLUSPLUS; - return PLUSPLUS; - } - if (c1 == '-' && c2 == '-') { - shift(2); - if (m_terminator) - return AUTOMINUSMINUS; - return MINUSMINUS; - } - if (c1 == '=' && c2 == '=') { - shift(2); - return EQEQ; - } - if (c1 == '+' && c2 == '=') { - shift(2); - return PLUSEQUAL; - } - if (c1 == '-' && c2 == '=') { - shift(2); - return MINUSEQUAL; - } - if (c1 == '*' && c2 == '=') { - shift(2); - return MULTEQUAL; - } - if (c1 == '/' && c2 == '=') { - shift(2); - return DIVEQUAL; - } - if (c1 == '&' && c2 == '=') { - shift(2); - return ANDEQUAL; - } - if (c1 == '^' && c2 == '=') { - shift(2); - return XOREQUAL; - } - if (c1 == '%' && c2 == '=') { - shift(2); - return MODEQUAL; - } - if (c1 == '|' && c2 == '=') { - shift(2); - return OREQUAL; - } - if (c1 == '<' && c2 == '<') { - shift(2); - return LSHIFT; - } - if (c1 == '>' && c2 == '>') { - shift(2); - return RSHIFT; - } - if (c1 == '&' && c2 == '&') { - shift(2); - return AND; - } - if (c1 == '|' && c2 == '|') { - shift(2); - return OR; - } - - switch (c1) { - case '=': - case '>': - case '<': - case ',': - case '!': - case '~': - case '?': - case ':': - case '.': - case '+': - case '-': - case '*': - case '/': - case '&': - case '|': - case '^': - case '%': - case '(': - case ')': - case '[': - case ']': - case ';': - shift(1); - return static_cast<int>(c1); - case '{': - charPos = m_position - 4; - shift(1); - return OPENBRACE; - case '}': - charPos = m_position - 4; - shift(1); - return CLOSEBRACE; - default: - return -1; - } -} - -unsigned short Lexer::singleEscape(unsigned short c) -{ - switch (c) { - case 'b': - return 0x08; - case 't': - return 0x09; - case 'n': - return 0x0A; - case 'v': - return 0x0B; - case 'f': - return 0x0C; - case 'r': - return 0x0D; - case '"': - return 0x22; - case '\'': - return 0x27; - case '\\': - return 0x5C; - default: - return c; - } -} - -unsigned short Lexer::convertOctal(int c1, int c2, int c3) -{ - return static_cast<unsigned short>((c1 - '0') * 64 + (c2 - '0') * 8 + c3 - '0'); -} - -unsigned char Lexer::convertHex(int c) -{ - if (c >= '0' && c <= '9') - return static_cast<unsigned char>(c - '0'); - if (c >= 'a' && c <= 'f') - return static_cast<unsigned char>(c - 'a' + 10); - return static_cast<unsigned char>(c - 'A' + 10); -} - -unsigned char Lexer::convertHex(int c1, int c2) -{ - return ((convertHex(c1) << 4) + convertHex(c2)); -} - -UChar Lexer::convertUnicode(int c1, int c2, int c3, int c4) -{ - unsigned char highByte = (convertHex(c1) << 4) + convertHex(c2); - unsigned char lowByte = (convertHex(c3) << 4) + convertHex(c4); - return (highByte << 8 | lowByte); -} - -void Lexer::record8(int c) -{ - ASSERT(c >= 0); - ASSERT(c <= 0xff); - m_buffer8.append(static_cast<char>(c)); -} - -void Lexer::record16(int c) -{ - ASSERT(c >= 0); - ASSERT(c <= USHRT_MAX); - record16(UChar(static_cast<unsigned short>(c))); -} - -void Lexer::record16(UChar c) -{ - m_buffer16.append(c); -} - -bool Lexer::scanRegExp() -{ - m_buffer16.clear(); - bool lastWasEscape = false; - bool inBrackets = false; - - while (1) { - if (isLineTerminator() || m_current == -1) - return false; - else if (m_current != '/' || lastWasEscape == true || inBrackets == true) { - // keep track of '[' and ']' - if (!lastWasEscape) { - if ( m_current == '[' && !inBrackets ) - inBrackets = true; - if ( m_current == ']' && inBrackets ) - inBrackets = false; - } - record16(m_current); - lastWasEscape = - !lastWasEscape && (m_current == '\\'); - } else { // end of regexp - m_pattern = UString(m_buffer16); - m_buffer16.clear(); - shift(1); - break; - } - shift(1); - } - - while (isIdentPart(m_current)) { - record16(m_current); - shift(1); - } - m_flags = UString(m_buffer16); - - return true; -} - -void Lexer::clear() -{ - deleteAllValues(m_strings); - Vector<UString*> newStrings; - newStrings.reserveCapacity(initialStringTableCapacity); - m_strings.swap(newStrings); - - deleteAllValues(m_identifiers); - Vector<JSC::Identifier*> newIdentifiers; - newIdentifiers.reserveCapacity(initialStringTableCapacity); - m_identifiers.swap(newIdentifiers); - - Vector<char> newBuffer8; - newBuffer8.reserveCapacity(initialReadBufferCapacity); - m_buffer8.swap(newBuffer8); - - Vector<UChar> newBuffer16; - newBuffer16.reserveCapacity(initialReadBufferCapacity); - m_buffer16.swap(newBuffer16); - - m_pattern = 0; - m_flags = 0; -} - -Identifier* Lexer::makeIdentifier(const Vector<UChar>& buffer) -{ - JSC::Identifier* identifier = new JSC::Identifier(m_globalData, buffer.data(), buffer.size()); - m_identifiers.append(identifier); - return identifier; -} - -} // namespace JSC diff --git a/JavaScriptCore/kjs/lexer.h b/JavaScriptCore/kjs/lexer.h deleted file mode 100644 index 16bc4b6..0000000 --- a/JavaScriptCore/kjs/lexer.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * This file is part of the KDE libraries - * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2007 Apple Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#ifndef Lexer_h -#define Lexer_h - -#include "lookup.h" -#include "ustring.h" -#include <wtf/Vector.h> -#include "SourceCode.h" - -namespace JSC { - - class Identifier; - class RegExp; - - class Lexer : Noncopyable { - public: - void setCode(const SourceCode&); - int lex(void* lvalp, void* llocp); - - int lineNo() const { return yylineno; } - - bool prevTerminator() const { return m_terminator; } - - enum State { - Start, - IdentifierOrKeyword, - Identifier, - InIdentifierOrKeyword, - InIdentifier, - InIdentifierStartUnicodeEscapeStart, - InIdentifierStartUnicodeEscape, - InIdentifierPartUnicodeEscapeStart, - InIdentifierPartUnicodeEscape, - InSingleLineComment, - InMultiLineComment, - InNum, - InNum0, - InHex, - InOctal, - InDecimal, - InExponentIndicator, - InExponent, - Hex, - Octal, - Number, - String, - Eof, - InString, - InEscapeSequence, - InHexEscape, - InUnicodeEscape, - Other, - Bad - }; - - bool scanRegExp(); - const UString& pattern() const { return m_pattern; } - const UString& flags() const { return m_flags; } - - static unsigned char convertHex(int); - static unsigned char convertHex(int c1, int c2); - static UChar convertUnicode(int c1, int c2, int c3, int c4); - static bool isIdentStart(int); - static bool isIdentPart(int); - static bool isHexDigit(int); - - bool sawError() const { return m_error; } - - void clear(); - SourceCode sourceCode(int openBrace, int closeBrace, int firstLine) { return SourceCode(m_source->provider(), m_source->startOffset() + openBrace + 1, m_source->startOffset() + closeBrace, firstLine); } - - private: - friend class JSGlobalData; - Lexer(JSGlobalData*); - ~Lexer(); - - void setDone(State); - void shift(unsigned int p); - void nextLine(); - int lookupKeyword(const char *); - - bool isWhiteSpace() const; - bool isLineTerminator(); - static bool isOctalDigit(int); - - int matchPunctuator(int& charPos, int c1, int c2, int c3, int c4); - static unsigned short singleEscape(unsigned short); - static unsigned short convertOctal(int c1, int c2, int c3); - - void record8(int); - void record16(int); - void record16(UChar); - - JSC::Identifier* makeIdentifier(const Vector<UChar>& buffer); - - int yylineno; - int yycolumn; - - bool m_done; - Vector<char> m_buffer8; - Vector<UChar> m_buffer16; - bool m_terminator; - bool m_restrKeyword; - bool m_delimited; // encountered delimiter like "'" and "}" on last run - bool m_skipLF; - bool m_skipCR; - bool m_eatNextIdentifier; - int m_stackToken; - int m_lastToken; - - State m_state; - unsigned int m_position; - const SourceCode* m_source; - const UChar* m_code; - unsigned int m_length; - int m_atLineStart; - bool m_error; - - // current and following unicode characters (int to allow for -1 for end-of-file marker) - int m_current; - int m_next1; - int m_next2; - int m_next3; - - int m_currentOffset; - int m_nextOffset1; - int m_nextOffset2; - int m_nextOffset3; - - Vector<UString*> m_strings; - Vector<JSC::Identifier*> m_identifiers; - - JSGlobalData* m_globalData; - - UString m_pattern; - UString m_flags; - - const HashTable m_mainTable; - }; - -} // namespace JSC - -#endif // Lexer_h diff --git a/JavaScriptCore/kjs/lookup.cpp b/JavaScriptCore/kjs/lookup.cpp deleted file mode 100644 index 41ac725..0000000 --- a/JavaScriptCore/kjs/lookup.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2008 Apple Inc. 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 - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "config.h" -#include "lookup.h" - -#include "PrototypeFunction.h" - -namespace JSC { - -void HashTable::createTable(JSGlobalData* globalData) const -{ - ASSERT(!table); - HashEntry* entries = new HashEntry[hashSizeMask + 1]; - for (int i = 0; i <= hashSizeMask; ++i) - entries[i].setKey(0); - for (int i = 0; values[i].key; ++i) { - UString::Rep* identifier = Identifier::add(globalData, values[i].key).releaseRef(); - int hashIndex = identifier->computedHash() & hashSizeMask; - ASSERT(!entries[hashIndex].key()); - entries[hashIndex].initialize(identifier, values[i].attributes, values[i].value1, values[i].value2); - } - table = entries; -} - -void HashTable::deleteTable() const -{ - if (table) { - for (int i = 0; i != hashSizeMask + 1; ++i) { - if (UString::Rep* key = table[i].key()) - key->deref(); - } - delete [] table; - table = 0; - } -} - -void setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot) -{ - ASSERT(entry->attributes() & Function); - JSValue** location = thisObj->getDirectLocation(propertyName); - - if (!location) { - PrototypeFunction* function = new (exec) PrototypeFunction(exec, entry->functionLength(), propertyName, entry->function()); - thisObj->putDirect(propertyName, function, entry->attributes()); - location = thisObj->getDirectLocation(propertyName); - } - - slot.setValueSlot(thisObj, location, thisObj->offsetForLocation(location)); -} - -} // namespace JSC diff --git a/JavaScriptCore/kjs/lookup.h b/JavaScriptCore/kjs/lookup.h deleted file mode 100644 index a547613..0000000 --- a/JavaScriptCore/kjs/lookup.h +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2006, 2007, 2008 Apple Inc. 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 - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef KJS_lookup_h -#define KJS_lookup_h - -#include "ExecState.h" -#include "JSFunction.h" -#include "JSGlobalObject.h" -#include "JSObject.h" -#include "PropertySlot.h" -#include "identifier.h" -#include <stdio.h> -#include <wtf/Assertions.h> - -namespace JSC { - - // Hash table generated by the create_hash_table script. - struct HashTableValue { - const char* key; // property name - unsigned char attributes; // JSObject attributes - intptr_t value1; - intptr_t value2; - }; - - // FIXME: There is no reason this get function can't be simpler. - // ie. typedef JSValue* (*GetFunction)(ExecState*, JSObject* baseObject) - typedef PropertySlot::GetValueFunc GetFunction; - typedef void (*PutFunction)(ExecState*, JSObject* baseObject, JSValue* value); - - class HashEntry { - public: - void initialize(UString::Rep* key, unsigned char attributes, intptr_t v1, intptr_t v2) - { - m_key = key; - m_attributes = attributes; - m_u.store.value1 = v1; - m_u.store.value2 = v2; - } - - void setKey(UString::Rep* key) { m_key = key; } - UString::Rep* key() const { return m_key; } - - unsigned char attributes() const { return m_attributes; } - - NativeFunction function() const { ASSERT(m_attributes & Function); return m_u.function.functionValue; } - unsigned char functionLength() const { ASSERT(m_attributes & Function); return static_cast<unsigned char>(m_u.function.length); } - - GetFunction propertyGetter() const { ASSERT(!(m_attributes & Function)); return m_u.property.get; } - PutFunction propertyPutter() const { ASSERT(!(m_attributes & Function)); return m_u.property.put; } - - intptr_t lexerValue() const { ASSERT(!m_attributes); return m_u.lexer.value; } - - private: - UString::Rep* m_key; - unsigned char m_attributes; // JSObject attributes - - union { - struct { - intptr_t value1; - intptr_t value2; - } store; - struct { - NativeFunction functionValue; - intptr_t length; // number of arguments for function - } function; - struct { - GetFunction get; - PutFunction put; - } property; - struct { - intptr_t value; - intptr_t unused; - } lexer; - } m_u; - }; - - struct HashTable { - int hashSizeMask; // Precomputed size for the hash table (minus 1). - const HashTableValue* values; // Fixed values generated by script. - mutable const HashEntry* table; // Table allocated at runtime. - - ALWAYS_INLINE void initializeIfNeeded(JSGlobalData* globalData) const - { - if (!table) - createTable(globalData); - } - - ALWAYS_INLINE void initializeIfNeeded(ExecState* exec) const - { - if (!table) - createTable(&exec->globalData()); - } - - void deleteTable() const; - - // Find an entry in the table, and return the entry. - ALWAYS_INLINE const HashEntry* entry(JSGlobalData* globalData, const Identifier& identifier) const - { - initializeIfNeeded(globalData); - return entry(identifier); - } - - ALWAYS_INLINE const HashEntry* entry(ExecState* exec, const Identifier& identifier) const - { - initializeIfNeeded(exec); - return entry(identifier); - } - - private: - ALWAYS_INLINE const HashEntry* entry(const Identifier& identifier) const - { - ASSERT(table); - const HashEntry* entry = &table[identifier.ustring().rep()->computedHash() & hashSizeMask]; - if (entry->key() != identifier.ustring().rep()) - return 0; - return entry; - } - - // Convert the hash table keys to identifiers. - void createTable(JSGlobalData*) const; - }; - - void setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, const Identifier& propertyName, PropertySlot&); - - /** - * This method does it all (looking in the hashtable, checking for function - * overrides, creating the function or retrieving from cache, calling - * getValueProperty in case of a non-function property, forwarding to parent if - * unknown property). - */ - template <class ThisImp, class ParentImp> - inline bool getStaticPropertySlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot) - { - const HashEntry* entry = table->entry(exec, propertyName); - - if (!entry) // not found, forward to parent - return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot); - - if (entry->attributes() & Function) - setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot); - else - slot.setCustom(thisObj, entry->propertyGetter()); - - return true; - } - - /** - * Simplified version of getStaticPropertySlot in case there are only functions. - * Using this instead of getStaticPropertySlot allows 'this' to avoid implementing - * a dummy getValueProperty. - */ - template <class ParentImp> - inline bool getStaticFunctionSlot(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot) - { - if (static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertySlot(exec, propertyName, slot)) - return true; - - const HashEntry* entry = table->entry(exec, propertyName); - if (!entry) - return false; - - setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot); - return true; - } - - /** - * Simplified version of getStaticPropertySlot in case there are no functions, only "values". - * Using this instead of getStaticPropertySlot removes the need for a FuncImp class. - */ - template <class ThisImp, class ParentImp> - inline bool getStaticValueSlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot) - { - const HashEntry* entry = table->entry(exec, propertyName); - - if (!entry) // not found, forward to parent - return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot); - - ASSERT(!(entry->attributes() & Function)); - - slot.setCustom(thisObj, entry->propertyGetter()); - return true; - } - - /** - * This one is for "put". - * It looks up a hash entry for the property to be set. If an entry - * is found it sets the value and returns true, else it returns false. - */ - template <class ThisImp> - inline bool lookupPut(ExecState* exec, const Identifier& propertyName, JSValue* value, const HashTable* table, ThisImp* thisObj) - { - const HashEntry* entry = table->entry(exec, propertyName); - - if (!entry) - return false; - - if (entry->attributes() & Function) // function: put as override property - thisObj->putDirect(propertyName, value); - else if (!(entry->attributes() & ReadOnly)) - entry->propertyPutter()(exec, thisObj, value); - - return true; - } - - /** - * This one is for "put". - * It calls lookupPut<ThisImp>() to set the value. If that call - * returns false (meaning no entry in the hash table was found), - * then it calls put() on the ParentImp class. - */ - template <class ThisImp, class ParentImp> - inline void lookupPut(ExecState* exec, const Identifier& propertyName, JSValue* value, const HashTable* table, ThisImp* thisObj, PutPropertySlot& slot) - { - if (!lookupPut<ThisImp>(exec, propertyName, value, table, thisObj)) - thisObj->ParentImp::put(exec, propertyName, value, slot); // not found: forward to parent - } - -} // namespace JSC - -#endif // KJS_lookup_h diff --git a/JavaScriptCore/kjs/nodes.cpp b/JavaScriptCore/kjs/nodes.cpp deleted file mode 100644 index b4aeb28..0000000 --- a/JavaScriptCore/kjs/nodes.cpp +++ /dev/null @@ -1,1882 +0,0 @@ -/* -* Copyright (C) 1999-2002 Harri Porten (porten@kde.org) -* Copyright (C) 2001 Peter Kelly (pmk@post.com) -* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. -* Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) -* Copyright (C) 2007 Maks Orlovich -* Copyright (C) 2007 Eric Seidel <eric@webkit.org> -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Library General Public -* License as published by the Free Software Foundation; either -* version 2 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Library General Public License for more details. -* -* You should have received a copy of the GNU Library General Public License -* along with this library; see the file COPYING.LIB. If not, write to -* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -* Boston, MA 02110-1301, USA. -* -*/ - -#include "config.h" -#include "nodes.h" - -#include "CodeGenerator.h" -#include "ExecState.h" -#include "JSGlobalObject.h" -#include "JSStaticScopeObject.h" -#include "LabelScope.h" -#include "Parser.h" -#include "PropertyNameArray.h" -#include "RegExpObject.h" -#include "SamplingTool.h" -#include "Debugger.h" -#include "lexer.h" -#include "operations.h" -#include <math.h> -#include <wtf/Assertions.h> -#include <wtf/HashCountedSet.h> -#include <wtf/HashSet.h> -#include <wtf/MathExtras.h> -#include <wtf/RefCountedLeakCounter.h> -#include <wtf/Threading.h> - -using namespace WTF; - -namespace JSC { - -// ------------------------------ Node ----------------------------------------- - -#ifndef NDEBUG -static RefCountedLeakCounter parserRefCountedCounter("JSC::Node"); -#endif - -ParserRefCounted::ParserRefCounted(JSGlobalData* globalData) - : m_globalData(globalData) -{ -#ifndef NDEBUG - parserRefCountedCounter.increment(); -#endif - if (!m_globalData->newParserObjects) - m_globalData->newParserObjects = new HashSet<ParserRefCounted*>; - m_globalData->newParserObjects->add(this); - ASSERT(m_globalData->newParserObjects->contains(this)); -} - -ParserRefCounted::~ParserRefCounted() -{ -#ifndef NDEBUG - parserRefCountedCounter.decrement(); -#endif -} - -void ParserRefCounted::ref() -{ - // bumping from 0 to 1 is just removing from the new nodes set - if (m_globalData->newParserObjects) { - HashSet<ParserRefCounted*>::iterator it = m_globalData->newParserObjects->find(this); - if (it != m_globalData->newParserObjects->end()) { - m_globalData->newParserObjects->remove(it); - ASSERT(!m_globalData->parserObjectExtraRefCounts || !m_globalData->parserObjectExtraRefCounts->contains(this)); - return; - } - } - - ASSERT(!m_globalData->newParserObjects || !m_globalData->newParserObjects->contains(this)); - - if (!m_globalData->parserObjectExtraRefCounts) - m_globalData->parserObjectExtraRefCounts = new HashCountedSet<ParserRefCounted*>; - m_globalData->parserObjectExtraRefCounts->add(this); -} - -void ParserRefCounted::deref() -{ - ASSERT(!m_globalData->newParserObjects || !m_globalData->newParserObjects->contains(this)); - - if (!m_globalData->parserObjectExtraRefCounts) { - delete this; - return; - } - - HashCountedSet<ParserRefCounted*>::iterator it = m_globalData->parserObjectExtraRefCounts->find(this); - if (it == m_globalData->parserObjectExtraRefCounts->end()) - delete this; - else - m_globalData->parserObjectExtraRefCounts->remove(it); -} - -bool ParserRefCounted::hasOneRef() -{ - if (m_globalData->newParserObjects && m_globalData->newParserObjects->contains(this)) { - ASSERT(!m_globalData->parserObjectExtraRefCounts || !m_globalData->parserObjectExtraRefCounts->contains(this)); - return false; - } - - ASSERT(!m_globalData->newParserObjects || !m_globalData->newParserObjects->contains(this)); - - if (!m_globalData->parserObjectExtraRefCounts) - return true; - - return !m_globalData->parserObjectExtraRefCounts->contains(this); -} - -void ParserRefCounted::deleteNewObjects(JSGlobalData* globalData) -{ - if (!globalData->newParserObjects) - return; - -#ifndef NDEBUG - HashSet<ParserRefCounted*>::iterator end = globalData->newParserObjects->end(); - for (HashSet<ParserRefCounted*>::iterator it = globalData->newParserObjects->begin(); it != end; ++it) - ASSERT(!globalData->parserObjectExtraRefCounts || !globalData->parserObjectExtraRefCounts->contains(*it)); -#endif - deleteAllValues(*globalData->newParserObjects); - delete globalData->newParserObjects; - globalData->newParserObjects = 0; -} - -Node::Node(JSGlobalData* globalData) - : ParserRefCounted(globalData) -{ - m_line = globalData->lexer->lineNo(); -} - -static void substitute(UString& string, const UString& substring) JSC_FAST_CALL; -static void substitute(UString& string, const UString& substring) -{ - int position = string.find("%s"); - ASSERT(position != -1); - UString newString = string.substr(0, position); - newString.append(substring); - newString.append(string.substr(position + 2)); - string = newString; -} - -RegisterID* ThrowableExpressionData::emitThrowError(CodeGenerator& generator, ErrorType e, const char* msg) -{ - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - RegisterID* exception = generator.emitNewError(generator.newTemporary(), e, jsString(generator.globalData(), msg)); - generator.emitThrow(exception); - return exception; -} - -RegisterID* ThrowableExpressionData::emitThrowError(CodeGenerator& generator, ErrorType e, const char* msg, const Identifier& label) -{ - UString message = msg; - substitute(message, label.ustring()); - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - RegisterID* exception = generator.emitNewError(generator.newTemporary(), e, jsString(generator.globalData(), message)); - generator.emitThrow(exception); - return exception; -} - -// ------------------------------ StatementNode -------------------------------- - -StatementNode::StatementNode(JSGlobalData* globalData) - : Node(globalData) - , m_lastLine(-1) -{ -} - -void StatementNode::setLoc(int firstLine, int lastLine) -{ - m_line = firstLine; - m_lastLine = lastLine; -} - -// ------------------------------ SourceElements -------------------------------- - -void SourceElements::append(PassRefPtr<StatementNode> statement) -{ - if (statement->isEmptyStatement()) - return; - - m_statements.append(statement); -} - -// ------------------------------ NullNode ------------------------------------- - -RegisterID* NullNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - if (dst == ignoredResult()) - return 0; - return generator.emitLoad(dst, jsNull()); -} - -// ------------------------------ BooleanNode ---------------------------------- - -RegisterID* BooleanNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - if (dst == ignoredResult()) - return 0; - return generator.emitLoad(dst, m_value); -} - -// ------------------------------ NumberNode ----------------------------------- - -RegisterID* NumberNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - if (dst == ignoredResult()) - return 0; - return generator.emitLoad(dst, m_double); -} - -// ------------------------------ StringNode ----------------------------------- - -RegisterID* StringNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - if (dst == ignoredResult()) - return 0; - return generator.emitLoad(dst, m_value); -} - -// ------------------------------ RegExpNode ----------------------------------- - -RegisterID* RegExpNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegExp> regExp = RegExp::create(generator.globalData(), m_pattern, m_flags); - if (!regExp->isValid()) - return emitThrowError(generator, SyntaxError, ("Invalid regular expression: " + UString(regExp->errorMessage())).UTF8String().c_str()); - if (dst == ignoredResult()) - return 0; - return generator.emitNewRegExp(generator.finalDestination(dst), regExp.get()); -} - -// ------------------------------ ThisNode ------------------------------------- - -RegisterID* ThisNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - if (dst == ignoredResult()) - return 0; - return generator.moveToDestinationIfNeeded(dst, generator.thisRegister()); -} - -// ------------------------------ ResolveNode ---------------------------------- - -bool ResolveNode::isPure(CodeGenerator& generator) const -{ - return generator.isLocal(m_ident); -} - -RegisterID* ResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - if (RegisterID* local = generator.registerFor(m_ident)) { - if (dst == ignoredResult()) - return 0; - return generator.moveToDestinationIfNeeded(dst, local); - } - - generator.emitExpressionInfo(m_startOffset + m_ident.size(), m_ident.size(), 0); - return generator.emitResolve(generator.finalDestination(dst), m_ident); -} - -// ------------------------------ ArrayNode ------------------------------------ - -RegisterID* ArrayNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - // FIXME: Should we put all of this code into emitNewArray? - - unsigned length = 0; - ElementNode* firstPutElement; - for (firstPutElement = m_element.get(); firstPutElement; firstPutElement = firstPutElement->next()) { - if (firstPutElement->elision()) - break; - ++length; - } - - if (!firstPutElement && !m_elision) - return generator.emitNewArray(generator.finalDestination(dst), m_element.get()); - - RefPtr<RegisterID> array = generator.emitNewArray(generator.tempDestination(dst), m_element.get()); - - for (ElementNode* n = firstPutElement; n; n = n->next()) { - RegisterID* value = generator.emitNode(n->value()); - length += n->elision(); - generator.emitPutByIndex(array.get(), length++, value); - } - - if (m_elision) { - RegisterID* value = generator.emitLoad(0, jsNumber(generator.globalData(), m_elision + length)); - generator.emitPutById(array.get(), generator.propertyNames().length, value); - } - - return generator.moveToDestinationIfNeeded(dst, array.get()); -} - -// ------------------------------ ObjectLiteralNode ---------------------------- - -RegisterID* ObjectLiteralNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - if (!m_list) { - if (dst == ignoredResult()) - return 0; - return generator.emitNewObject(generator.finalDestination(dst)); - } - return generator.emitNode(dst, m_list.get()); -} - -// ------------------------------ PropertyListNode ----------------------------- - -RegisterID* PropertyListNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> newObj = generator.tempDestination(dst); - - generator.emitNewObject(newObj.get()); - - for (PropertyListNode* p = this; p; p = p->m_next.get()) { - RegisterID* value = generator.emitNode(p->m_node->m_assign.get()); - - switch (p->m_node->m_type) { - case PropertyNode::Constant: { - generator.emitPutById(newObj.get(), p->m_node->name(), value); - break; - } - case PropertyNode::Getter: { - generator.emitPutGetter(newObj.get(), p->m_node->name(), value); - break; - } - case PropertyNode::Setter: { - generator.emitPutSetter(newObj.get(), p->m_node->name(), value); - break; - } - default: - ASSERT_NOT_REACHED(); - } - } - - return generator.moveToDestinationIfNeeded(dst, newObj.get()); -} - -// ------------------------------ BracketAccessorNode -------------------------------- - -RegisterID* BracketAccessorNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_subscriptHasAssignments, m_subscript->isPure(generator)); - RegisterID* property = generator.emitNode(m_subscript.get()); - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - return generator.emitGetByVal(generator.finalDestination(dst), base.get(), property); -} - -// ------------------------------ DotAccessorNode -------------------------------- - -RegisterID* DotAccessorNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RegisterID* base = generator.emitNode(m_base.get()); - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - return generator.emitGetById(generator.finalDestination(dst), base, m_ident); -} - -// ------------------------------ ArgumentListNode ----------------------------- - -RegisterID* ArgumentListNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - ASSERT(m_expr); - return generator.emitNode(dst, m_expr.get()); -} - -// ------------------------------ NewExprNode ---------------------------------- - -RegisterID* NewExprNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> func = generator.emitNode(m_expr.get()); - return generator.emitConstruct(generator.finalDestination(dst), func.get(), m_args.get(), m_divot, m_startOffset, m_endOffset); -} - -RegisterID* EvalFunctionCallNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.tempDestination(dst); - RefPtr<RegisterID> func = generator.newTemporary(); - generator.emitResolveWithBase(base.get(), func.get(), generator.propertyNames().eval); - return generator.emitCallEval(generator.finalDestination(dst, base.get()), func.get(), base.get(), m_args.get(), m_divot, m_startOffset, m_endOffset); -} - -RegisterID* FunctionCallValueNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> func = generator.emitNode(m_expr.get()); - return generator.emitCall(generator.finalDestination(dst), func.get(), 0, m_args.get(), m_divot, m_startOffset, m_endOffset); -} - -RegisterID* FunctionCallResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - if (RefPtr<RegisterID> local = generator.registerFor(m_ident)) - return generator.emitCall(generator.finalDestination(dst), local.get(), 0, m_args.get(), m_divot, m_startOffset, m_endOffset); - - int index = 0; - size_t depth = 0; - JSObject* globalObject = 0; - if (generator.findScopedProperty(m_ident, index, depth, false, globalObject) && index != missingSymbolMarker()) { - RefPtr<RegisterID> func = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject); - return generator.emitCall(generator.finalDestination(dst), func.get(), 0, m_args.get(), m_divot, m_startOffset, m_endOffset); - } - - RefPtr<RegisterID> base = generator.tempDestination(dst); - RefPtr<RegisterID> func = generator.newTemporary(); - int identifierStart = m_divot - m_startOffset; - generator.emitExpressionInfo(identifierStart + m_ident.size(), m_ident.size(), 0); - generator.emitResolveFunction(base.get(), func.get(), m_ident); - return generator.emitCall(generator.finalDestination(dst, base.get()), func.get(), base.get(), m_args.get(), m_divot, m_startOffset, m_endOffset); -} - -RegisterID* FunctionCallBracketNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNode(m_base.get()); - RegisterID* property = generator.emitNode(m_subscript.get()); - generator.emitExpressionInfo(m_divot - m_subexpressionDivotOffset, m_startOffset - m_subexpressionDivotOffset, m_subexpressionEndOffset); - RefPtr<RegisterID> function = generator.emitGetByVal(generator.newTemporary(), base.get(), property); - return generator.emitCall(generator.finalDestination(dst, base.get()), function.get(), base.get(), m_args.get(), m_divot, m_startOffset, m_endOffset); -} - -RegisterID* FunctionCallDotNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNode(m_base.get()); - generator.emitExpressionInfo(m_divot - m_subexpressionDivotOffset, m_startOffset - m_subexpressionDivotOffset, m_subexpressionEndOffset); - RefPtr<RegisterID> function = generator.emitGetById(generator.newTemporary(), base.get(), m_ident); - return generator.emitCall(generator.finalDestination(dst, base.get()), function.get(), base.get(), m_args.get(), m_divot, m_startOffset, m_endOffset); -} - -// ------------------------------ PostfixResolveNode ---------------------------------- - -static RegisterID* emitPreIncOrDec(CodeGenerator& generator, RegisterID* srcDst, Operator oper) -{ - return (oper == OpPlusPlus) ? generator.emitPreInc(srcDst) : generator.emitPreDec(srcDst); -} - -static RegisterID* emitPostIncOrDec(CodeGenerator& generator, RegisterID* dst, RegisterID* srcDst, Operator oper) -{ - return (oper == OpPlusPlus) ? generator.emitPostInc(dst, srcDst) : generator.emitPostDec(dst, srcDst); -} - -RegisterID* PostfixResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - if (RegisterID* local = generator.registerFor(m_ident)) { - if (generator.isLocalConstant(m_ident)) { - if (dst == ignoredResult()) - return 0; - return generator.emitToJSNumber(generator.finalDestination(dst), local); - } - - if (dst == ignoredResult()) - return emitPreIncOrDec(generator, local, m_operator); - return emitPostIncOrDec(generator, generator.finalDestination(dst), local, m_operator); - } - - int index = 0; - size_t depth = 0; - JSObject* globalObject = 0; - if (generator.findScopedProperty(m_ident, index, depth, true, globalObject) && index != missingSymbolMarker()) { - RefPtr<RegisterID> value = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject); - RegisterID* oldValue; - if (dst == ignoredResult()) { - oldValue = 0; - emitPreIncOrDec(generator, value.get(), m_operator); - } else { - oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator); - } - generator.emitPutScopedVar(depth, index, value.get(), globalObject); - return oldValue; - } - - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - RefPtr<RegisterID> value = generator.newTemporary(); - RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), m_ident); - RegisterID* oldValue; - if (dst == ignoredResult()) { - oldValue = 0; - emitPreIncOrDec(generator, value.get(), m_operator); - } else { - oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator); - } - generator.emitPutById(base.get(), m_ident, value.get()); - return oldValue; -} - -// ------------------------------ PostfixBracketNode ---------------------------------- - -RegisterID* PostfixBracketNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNode(m_base.get()); - RefPtr<RegisterID> property = generator.emitNode(m_subscript.get()); - - generator.emitExpressionInfo(m_divot - m_subexpressionDivotOffset, m_startOffset - m_subexpressionDivotOffset, m_subexpressionEndOffset); - RefPtr<RegisterID> value = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get()); - RegisterID* oldValue; - if (dst == ignoredResult()) { - oldValue = 0; - if (m_operator == OpPlusPlus) - generator.emitPreInc(value.get()); - else - generator.emitPreDec(value.get()); - } else { - oldValue = (m_operator == OpPlusPlus) ? generator.emitPostInc(generator.finalDestination(dst), value.get()) : generator.emitPostDec(generator.finalDestination(dst), value.get()); - } - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - generator.emitPutByVal(base.get(), property.get(), value.get()); - return oldValue; -} - -// ------------------------------ PostfixDotNode ---------------------------------- - -RegisterID* PostfixDotNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNode(m_base.get()); - - generator.emitExpressionInfo(m_divot - m_subexpressionDivotOffset, m_startOffset - m_subexpressionDivotOffset, m_subexpressionEndOffset); - RefPtr<RegisterID> value = generator.emitGetById(generator.newTemporary(), base.get(), m_ident); - RegisterID* oldValue; - if (dst == ignoredResult()) { - oldValue = 0; - if (m_operator == OpPlusPlus) - generator.emitPreInc(value.get()); - else - generator.emitPreDec(value.get()); - } else { - oldValue = (m_operator == OpPlusPlus) ? generator.emitPostInc(generator.finalDestination(dst), value.get()) : generator.emitPostDec(generator.finalDestination(dst), value.get()); - } - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - generator.emitPutById(base.get(), m_ident, value.get()); - return oldValue; -} - -// ------------------------------ PostfixErrorNode ----------------------------------- - -RegisterID* PostfixErrorNode::emitCode(CodeGenerator& generator, RegisterID*) -{ - return emitThrowError(generator, ReferenceError, m_operator == OpPlusPlus ? "Postfix ++ operator applied to value that is not a reference." : "Postfix -- operator applied to value that is not a reference."); -} - -// ------------------------------ DeleteResolveNode ----------------------------------- - -RegisterID* DeleteResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - if (generator.registerFor(m_ident)) - return generator.emitUnexpectedLoad(generator.finalDestination(dst), false); - - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - RegisterID* base = generator.emitResolveBase(generator.tempDestination(dst), m_ident); - return generator.emitDeleteById(generator.finalDestination(dst, base), base, m_ident); -} - -// ------------------------------ DeleteBracketNode ----------------------------------- - -RegisterID* DeleteBracketNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> r0 = generator.emitNode(m_base.get()); - RegisterID* r1 = generator.emitNode(m_subscript.get()); - - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - return generator.emitDeleteByVal(generator.finalDestination(dst), r0.get(), r1); -} - -// ------------------------------ DeleteDotNode ----------------------------------- - -RegisterID* DeleteDotNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RegisterID* r0 = generator.emitNode(m_base.get()); - - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - return generator.emitDeleteById(generator.finalDestination(dst), r0, m_ident); -} - -// ------------------------------ DeleteValueNode ----------------------------------- - -RegisterID* DeleteValueNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - generator.emitNode(ignoredResult(), m_expr.get()); - - // delete on a non-location expression ignores the value and returns true - return generator.emitUnexpectedLoad(generator.finalDestination(dst), true); -} - -// ------------------------------ VoidNode ------------------------------------- - -RegisterID* VoidNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - if (dst == ignoredResult()) { - generator.emitNode(ignoredResult(), m_expr.get()); - return 0; - } - RefPtr<RegisterID> r0 = generator.emitNode(m_expr.get()); - return generator.emitLoad(dst, jsUndefined()); -} - -// ------------------------------ TypeOfValueNode ----------------------------------- - -RegisterID* TypeOfResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - if (RegisterID* local = generator.registerFor(m_ident)) { - if (dst == ignoredResult()) - return 0; - return generator.emitTypeOf(generator.finalDestination(dst), local); - } - - RefPtr<RegisterID> scratch = generator.emitResolveBase(generator.tempDestination(dst), m_ident); - generator.emitGetById(scratch.get(), scratch.get(), m_ident); - if (dst == ignoredResult()) - return 0; - return generator.emitTypeOf(generator.finalDestination(dst, scratch.get()), scratch.get()); -} - -// ------------------------------ TypeOfValueNode ----------------------------------- - -RegisterID* TypeOfValueNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - if (dst == ignoredResult()) { - generator.emitNode(ignoredResult(), m_expr.get()); - return 0; - } - RefPtr<RegisterID> src = generator.emitNode(m_expr.get()); - return generator.emitTypeOf(generator.finalDestination(dst), src.get()); -} - -// ------------------------------ PrefixResolveNode ---------------------------------- - -RegisterID* PrefixResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - if (RegisterID* local = generator.registerFor(m_ident)) { - if (generator.isLocalConstant(m_ident)) { - if (dst == ignoredResult()) - return 0; - RefPtr<RegisterID> r0 = generator.emitUnexpectedLoad(generator.finalDestination(dst), (m_operator == OpPlusPlus) ? 1.0 : -1.0); - return generator.emitBinaryOp(op_add, r0.get(), local, r0.get(), OperandTypes()); - } - - emitPreIncOrDec(generator, local, m_operator); - return generator.moveToDestinationIfNeeded(dst, local); - } - - int index = 0; - size_t depth = 0; - JSObject* globalObject = 0; - if (generator.findScopedProperty(m_ident, index, depth, false, globalObject) && index != missingSymbolMarker()) { - RefPtr<RegisterID> propDst = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index, globalObject); - emitPreIncOrDec(generator, propDst.get(), m_operator); - generator.emitPutScopedVar(depth, index, propDst.get(), globalObject); - return generator.moveToDestinationIfNeeded(dst, propDst.get()); - } - - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - RefPtr<RegisterID> propDst = generator.tempDestination(dst); - RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), propDst.get(), m_ident); - emitPreIncOrDec(generator, propDst.get(), m_operator); - generator.emitPutById(base.get(), m_ident, propDst.get()); - return generator.moveToDestinationIfNeeded(dst, propDst.get()); -} - -// ------------------------------ PrefixBracketNode ---------------------------------- - -RegisterID* PrefixBracketNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNode(m_base.get()); - RefPtr<RegisterID> property = generator.emitNode(m_subscript.get()); - RefPtr<RegisterID> propDst = generator.tempDestination(dst); - - generator.emitExpressionInfo(m_divot + m_subexpressionDivotOffset, m_subexpressionStartOffset, m_endOffset - m_subexpressionDivotOffset); - RegisterID* value = generator.emitGetByVal(propDst.get(), base.get(), property.get()); - if (m_operator == OpPlusPlus) - generator.emitPreInc(value); - else - generator.emitPreDec(value); - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - generator.emitPutByVal(base.get(), property.get(), value); - return generator.moveToDestinationIfNeeded(dst, propDst.get()); -} - -// ------------------------------ PrefixDotNode ---------------------------------- - -RegisterID* PrefixDotNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNode(m_base.get()); - RefPtr<RegisterID> propDst = generator.tempDestination(dst); - - generator.emitExpressionInfo(m_divot + m_subexpressionDivotOffset, m_subexpressionStartOffset, m_endOffset - m_subexpressionDivotOffset); - RegisterID* value = generator.emitGetById(propDst.get(), base.get(), m_ident); - if (m_operator == OpPlusPlus) - generator.emitPreInc(value); - else - generator.emitPreDec(value); - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - generator.emitPutById(base.get(), m_ident, value); - return generator.moveToDestinationIfNeeded(dst, propDst.get()); -} - -// ------------------------------ PrefixErrorNode ----------------------------------- - -RegisterID* PrefixErrorNode::emitCode(CodeGenerator& generator, RegisterID*) -{ - return emitThrowError(generator, ReferenceError, m_operator == OpPlusPlus ? "Prefix ++ operator applied to value that is not a reference." : "Prefix -- operator applied to value that is not a reference."); -} - -// ------------------------------ Unary Operation Nodes ----------------------------------- - -RegisterID* UnaryOpNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RegisterID* src = generator.emitNode(m_expr.get()); - return generator.emitUnaryOp(opcode(), generator.finalDestination(dst), src, m_expr->resultDescriptor()); -} - -// ------------------------------ Binary Operation Nodes ----------------------------------- - -RegisterID* BinaryOpNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - OpcodeID opcode = this->opcode(); - if (opcode == op_neq) { - if (m_expr1->isNull() || m_expr2->isNull()) { - RefPtr<RegisterID> src = generator.emitNode(dst, m_expr1->isNull() ? m_expr2.get() : m_expr1.get()); - return generator.emitUnaryOp(op_neq_null, generator.finalDestination(dst, src.get()), src.get(), ResultType::unknown()); - } - } - - RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator)); - RegisterID* src2 = generator.emitNode(m_expr2.get()); - return generator.emitBinaryOp(opcode, generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor())); -} - -RegisterID* EqualNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - if (m_expr1->isNull() || m_expr2->isNull()) { - RefPtr<RegisterID> src = generator.emitNode(dst, m_expr1->isNull() ? m_expr2.get() : m_expr1.get()); - return generator.emitUnaryOp(op_eq_null, generator.finalDestination(dst, src.get()), src.get(), ResultType::unknown()); - } - - RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator)); - RegisterID* src2 = generator.emitNode(m_expr2.get()); - return generator.emitEqualityOp(op_eq, generator.finalDestination(dst, src1.get()), src1.get(), src2); -} - -RegisterID* StrictEqualNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator)); - RegisterID* src2 = generator.emitNode(m_expr2.get()); - return generator.emitEqualityOp(op_stricteq, generator.finalDestination(dst, src1.get()), src1.get(), src2); -} - -RegisterID* ReverseBinaryOpNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator)); - RegisterID* src2 = generator.emitNode(m_expr2.get()); - return generator.emitBinaryOp(opcode(), generator.finalDestination(dst, src1.get()), src2, src1.get(), OperandTypes(m_expr2->resultDescriptor(), m_expr1->resultDescriptor())); -} - -RegisterID* ThrowableBinaryOpNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator)); - RegisterID* src2 = generator.emitNode(m_expr2.get()); - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - return generator.emitBinaryOp(opcode(), generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor())); -} - -RegisterID* InstanceOfNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator)); - RefPtr<RegisterID> src2 = generator.emitNode(m_expr2.get()); - - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - RegisterID* src2Prototype = generator.emitGetById(generator.newTemporary(), src2.get(), generator.globalData()->propertyNames->prototype); - - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - return generator.emitInstanceOf(generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), src2Prototype); -} - -// ------------------------------ Binary Logical Nodes ---------------------------- - -RegisterID* LogicalOpNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> temp = generator.tempDestination(dst); - RefPtr<LabelID> target = generator.newLabel(); - - generator.emitNode(temp.get(), m_expr1.get()); - if (m_operator == OpLogicalAnd) - generator.emitJumpIfFalse(temp.get(), target.get()); - else - generator.emitJumpIfTrue(temp.get(), target.get()); - generator.emitNode(temp.get(), m_expr2.get()); - generator.emitLabel(target.get()); - - return generator.moveToDestinationIfNeeded(dst, temp.get()); -} - -// ------------------------------ ConditionalNode ------------------------------ - -RegisterID* ConditionalNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> newDst = generator.finalDestination(dst); - RefPtr<LabelID> beforeElse = generator.newLabel(); - RefPtr<LabelID> afterElse = generator.newLabel(); - - RegisterID* cond = generator.emitNode(m_logical.get()); - generator.emitJumpIfFalse(cond, beforeElse.get()); - - generator.emitNode(newDst.get(), m_expr1.get()); - generator.emitJump(afterElse.get()); - - generator.emitLabel(beforeElse.get()); - generator.emitNode(newDst.get(), m_expr2.get()); - - generator.emitLabel(afterElse.get()); - - return newDst.get(); -} - -// ------------------------------ ReadModifyResolveNode ----------------------------------- - -// FIXME: should this be moved to be a method on CodeGenerator? -static ALWAYS_INLINE RegisterID* emitReadModifyAssignment(CodeGenerator& generator, RegisterID* dst, RegisterID* src1, RegisterID* src2, Operator oper, OperandTypes types) -{ - OpcodeID opcode; - switch (oper) { - case OpMultEq: - opcode = op_mul; - break; - case OpDivEq: - opcode = op_div; - break; - case OpPlusEq: - opcode = op_add; - break; - case OpMinusEq: - opcode = op_sub; - break; - case OpLShift: - opcode = op_lshift; - break; - case OpRShift: - opcode = op_rshift; - break; - case OpURShift: - opcode = op_urshift; - break; - case OpAndEq: - opcode = op_bitand; - break; - case OpXOrEq: - opcode = op_bitxor; - break; - case OpOrEq: - opcode = op_bitor; - break; - case OpModEq: - opcode = op_mod; - break; - default: - ASSERT_NOT_REACHED(); - return dst; - } - - return generator.emitBinaryOp(opcode, dst, src1, src2, types); -} - -RegisterID* ReadModifyResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - if (RegisterID* local = generator.registerFor(m_ident)) { - if (generator.isLocalConstant(m_ident)) { - RegisterID* src2 = generator.emitNode(m_right.get()); - return emitReadModifyAssignment(generator, generator.finalDestination(dst), local, src2, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor())); - } - - if (generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) { - RefPtr<RegisterID> result = generator.newTemporary(); - generator.emitMove(result.get(), local); - RegisterID* src2 = generator.emitNode(m_right.get()); - emitReadModifyAssignment(generator, result.get(), result.get(), src2, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor())); - generator.emitMove(local, result.get()); - return generator.moveToDestinationIfNeeded(dst, result.get()); - } - - RegisterID* src2 = generator.emitNode(m_right.get()); - RegisterID* result = emitReadModifyAssignment(generator, local, local, src2, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor())); - return generator.moveToDestinationIfNeeded(dst, result); - } - - int index = 0; - size_t depth = 0; - JSObject* globalObject = 0; - if (generator.findScopedProperty(m_ident, index, depth, true, globalObject) && index != missingSymbolMarker()) { - RefPtr<RegisterID> src1 = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index, globalObject); - RegisterID* src2 = generator.emitNode(m_right.get()); - RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), src2, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor())); - generator.emitPutScopedVar(depth, index, result, globalObject); - return result; - } - - RefPtr<RegisterID> src1 = generator.tempDestination(dst); - generator.emitExpressionInfo(m_divot - m_startOffset + m_ident.size(), m_ident.size(), 0); - RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), src1.get(), m_ident); - RegisterID* src2 = generator.emitNode(m_right.get()); - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), src2, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor())); - return generator.emitPutById(base.get(), m_ident, result); -} - -// ------------------------------ AssignResolveNode ----------------------------------- - -RegisterID* AssignResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - if (RegisterID* local = generator.registerFor(m_ident)) { - if (generator.isLocalConstant(m_ident)) - return generator.emitNode(dst, m_right.get()); - - RegisterID* result = generator.emitNode(local, m_right.get()); - return generator.moveToDestinationIfNeeded(dst, result); - } - - int index = 0; - size_t depth = 0; - JSObject* globalObject = 0; - if (generator.findScopedProperty(m_ident, index, depth, true, globalObject) && index != missingSymbolMarker()) { - if (dst == ignoredResult()) - dst = 0; - RegisterID* value = generator.emitNode(dst, m_right.get()); - generator.emitPutScopedVar(depth, index, value, globalObject); - return value; - } - - RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), m_ident); - if (dst == ignoredResult()) - dst = 0; - RegisterID* value = generator.emitNode(dst, m_right.get()); - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - return generator.emitPutById(base.get(), m_ident, value); -} - -// ------------------------------ AssignDotNode ----------------------------------- - -RegisterID* AssignDotNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_rightHasAssignments, m_right->isPure(generator)); - RefPtr<RegisterID> value = generator.destinationForAssignResult(dst); - RegisterID* result = generator.emitNode(value.get(), m_right.get()); - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - generator.emitPutById(base.get(), m_ident, result); - return generator.moveToDestinationIfNeeded(dst, result); -} - -// ------------------------------ ReadModifyDotNode ----------------------------------- - -RegisterID* ReadModifyDotNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_rightHasAssignments, m_right->isPure(generator)); - - generator.emitExpressionInfo(m_divot - m_subexpressionDivotOffset, m_startOffset - m_subexpressionDivotOffset, m_subexpressionEndOffset); - RefPtr<RegisterID> value = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident); - RegisterID* change = generator.emitNode(m_right.get()); - RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), change, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor())); - - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - return generator.emitPutById(base.get(), m_ident, updatedValue); -} - -// ------------------------------ AssignErrorNode ----------------------------------- - -RegisterID* AssignErrorNode::emitCode(CodeGenerator& generator, RegisterID*) -{ - return emitThrowError(generator, ReferenceError, "Left side of assignment is not a reference."); -} - -// ------------------------------ AssignBracketNode ----------------------------------- - -RegisterID* AssignBracketNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator)); - RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript.get(), m_rightHasAssignments, m_right->isPure(generator)); - RefPtr<RegisterID> value = generator.destinationForAssignResult(dst); - RegisterID* result = generator.emitNode(value.get(), m_right.get()); - - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - generator.emitPutByVal(base.get(), property.get(), result); - return generator.moveToDestinationIfNeeded(dst, result); -} - -RegisterID* ReadModifyBracketNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator)); - RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript.get(), m_rightHasAssignments, m_right->isPure(generator)); - - generator.emitExpressionInfo(m_divot - m_subexpressionDivotOffset, m_startOffset - m_subexpressionDivotOffset, m_subexpressionEndOffset); - RefPtr<RegisterID> value = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get()); - RegisterID* change = generator.emitNode(m_right.get()); - RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), change, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor())); - - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - generator.emitPutByVal(base.get(), property.get(), updatedValue); - - return updatedValue; -} - -// ------------------------------ CommaNode ------------------------------------ - -RegisterID* CommaNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - generator.emitNode(ignoredResult(), m_expr1.get()); - return generator.emitNode(dst, m_expr2.get()); -} - -// ------------------------------ ConstDeclNode ---------------------------------- - -ConstDeclNode::ConstDeclNode(JSGlobalData* globalData, const Identifier& ident, ExpressionNode* init) - : ExpressionNode(globalData) - , m_ident(ident) - , m_init(init) -{ -} - -RegisterID* ConstDeclNode::emitCodeSingle(CodeGenerator& generator) -{ - if (RegisterID* local = generator.constRegisterFor(m_ident)) { - if (!m_init) - return local; - - return generator.emitNode(local, m_init.get()); - } - - // FIXME: While this code should only be hit in eval code, it will potentially - // assign to the wrong base if m_ident exists in an intervening dynamic scope. - RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), m_ident); - RegisterID* value = m_init ? generator.emitNode(m_init.get()) : generator.emitLoad(0, jsUndefined()); - return generator.emitPutById(base.get(), m_ident, value); -} - -RegisterID* ConstDeclNode::emitCode(CodeGenerator& generator, RegisterID*) -{ - RegisterID* result = 0; - for (ConstDeclNode* n = this; n; n = n->m_next.get()) - result = n->emitCodeSingle(generator); - - return result; -} - -// ------------------------------ ConstStatementNode ----------------------------- - -RegisterID* ConstStatementNode::emitCode(CodeGenerator& generator, RegisterID*) -{ - return generator.emitNode(m_next.get()); -} - -// ------------------------------ Helper functions for handling Vectors of StatementNode ------------------------------- - -static inline RegisterID* statementListEmitCode(StatementVector& statements, CodeGenerator& generator, RegisterID* dst) -{ - StatementVector::iterator end = statements.end(); - for (StatementVector::iterator it = statements.begin(); it != end; ++it) { - StatementNode* n = it->get(); - if (!n->isLoop()) - generator.emitDebugHook(WillExecuteStatement, n->firstLine(), n->lastLine()); - generator.emitNode(dst, n); - } - return 0; -} - -static inline void statementListPushFIFO(StatementVector& statements, DeclarationStacks::NodeStack& stack) -{ - StatementVector::iterator it = statements.end(); - StatementVector::iterator begin = statements.begin(); - while (it != begin) { - --it; - stack.append((*it).get()); - } -} - -// ------------------------------ BlockNode ------------------------------------ - -BlockNode::BlockNode(JSGlobalData* globalData, SourceElements* children) - : StatementNode(globalData) -{ - if (children) - children->releaseContentsIntoVector(m_children); -} - -RegisterID* BlockNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - return statementListEmitCode(m_children, generator, dst); -} - -// ------------------------------ EmptyStatementNode --------------------------- - -RegisterID* EmptyStatementNode::emitCode(CodeGenerator&, RegisterID* dst) -{ - return dst; -} - -// ------------------------------ DebuggerStatementNode --------------------------- - -RegisterID* DebuggerStatementNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - generator.emitDebugHook(DidReachBreakpoint, firstLine(), lastLine()); - return dst; -} - -// ------------------------------ ExprStatementNode ---------------------------- - -RegisterID* ExprStatementNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - ASSERT(m_expr); - return generator.emitNode(dst, m_expr.get()); -} - -// ------------------------------ VarStatementNode ---------------------------- - -RegisterID* VarStatementNode::emitCode(CodeGenerator& generator, RegisterID*) -{ - ASSERT(m_expr); - return generator.emitNode(m_expr.get()); -} - -// ------------------------------ IfNode --------------------------------------- - -RegisterID* IfNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<LabelID> afterThen = generator.newLabel(); - - RegisterID* cond = generator.emitNode(m_condition.get()); - generator.emitJumpIfFalse(cond, afterThen.get()); - - if (!m_ifBlock->isBlock()) - generator.emitDebugHook(WillExecuteStatement, m_ifBlock->firstLine(), m_ifBlock->lastLine()); - - generator.emitNode(dst, m_ifBlock.get()); - generator.emitLabel(afterThen.get()); - - // FIXME: This should return the last statement exectuted so that it can be returned as a Completion - return 0; -} - -RegisterID* IfElseNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<LabelID> beforeElse = generator.newLabel(); - RefPtr<LabelID> afterElse = generator.newLabel(); - - RegisterID* cond = generator.emitNode(m_condition.get()); - generator.emitJumpIfFalse(cond, beforeElse.get()); - - if (!m_ifBlock->isBlock()) - generator.emitDebugHook(WillExecuteStatement, m_ifBlock->firstLine(), m_ifBlock->lastLine()); - - generator.emitNode(dst, m_ifBlock.get()); - generator.emitJump(afterElse.get()); - - generator.emitLabel(beforeElse.get()); - - if (!m_elseBlock->isBlock()) - generator.emitDebugHook(WillExecuteStatement, m_elseBlock->firstLine(), m_elseBlock->lastLine()); - - generator.emitNode(dst, m_elseBlock.get()); - - generator.emitLabel(afterElse.get()); - - // FIXME: This should return the last statement exectuted so that it can be returned as a Completion - return 0; -} - -// ------------------------------ DoWhileNode ---------------------------------- - -RegisterID* DoWhileNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); - - RefPtr<LabelID> topOfLoop = generator.newLabel(); - generator.emitLabel(topOfLoop.get()); - - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - if (!m_statement->isBlock()) - generator.emitDebugHook(WillExecuteStatement, m_statement->firstLine(), m_statement->lastLine()); - - RefPtr<RegisterID> result = generator.emitNode(dst, m_statement.get()); - - generator.emitLabel(scope->continueTarget()); - generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->lineNo()); - RegisterID* cond = generator.emitNode(m_expr.get()); - generator.emitJumpIfTrue(cond, topOfLoop.get()); - - generator.emitLabel(scope->breakTarget()); - return result.get(); -} - -// ------------------------------ WhileNode ------------------------------------ - -RegisterID* WhileNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); - - generator.emitJump(scope->continueTarget()); - - RefPtr<LabelID> topOfLoop = generator.newLabel(); - generator.emitLabel(topOfLoop.get()); - - if (!m_statement->isBlock()) - generator.emitDebugHook(WillExecuteStatement, m_statement->firstLine(), m_statement->lastLine()); - - generator.emitNode(dst, m_statement.get()); - - generator.emitLabel(scope->continueTarget()); - generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->lineNo()); - RegisterID* cond = generator.emitNode(m_expr.get()); - generator.emitJumpIfTrue(cond, topOfLoop.get()); - - generator.emitLabel(scope->breakTarget()); - - // FIXME: This should return the last statement executed so that it can be returned as a Completion - return 0; -} - -// ------------------------------ ForNode -------------------------------------- - -RegisterID* ForNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - if (dst == ignoredResult()) - dst = 0; - - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); - - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - if (m_expr1) - generator.emitNode(ignoredResult(), m_expr1.get()); - - RefPtr<LabelID> condition = generator.newLabel(); - generator.emitJump(condition.get()); - - RefPtr<LabelID> topOfLoop = generator.newLabel(); - generator.emitLabel(topOfLoop.get()); - - if (!m_statement->isBlock()) - generator.emitDebugHook(WillExecuteStatement, m_statement->firstLine(), m_statement->lastLine()); - RefPtr<RegisterID> result = generator.emitNode(dst, m_statement.get()); - - generator.emitLabel(scope->continueTarget()); - if (m_expr3) - generator.emitNode(ignoredResult(), m_expr3.get()); - - generator.emitLabel(condition.get()); - if (m_expr2) { - RegisterID* cond = generator.emitNode(m_expr2.get()); - generator.emitJumpIfTrue(cond, topOfLoop.get()); - } else - generator.emitJump(topOfLoop.get()); - - generator.emitLabel(scope->breakTarget()); - return result.get(); -} - -// ------------------------------ ForInNode ------------------------------------ - -ForInNode::ForInNode(JSGlobalData* globalData, ExpressionNode* l, ExpressionNode* expr, StatementNode* statement) - : StatementNode(globalData) - , m_init(0L) - , m_lexpr(l) - , m_expr(expr) - , m_statement(statement) - , m_identIsVarDecl(false) -{ -} - -ForInNode::ForInNode(JSGlobalData* globalData, const Identifier& ident, ExpressionNode* in, ExpressionNode* expr, StatementNode* statement, int divot, int startOffset, int endOffset) - : StatementNode(globalData) - , m_ident(ident) - , m_lexpr(new ResolveNode(globalData, ident, divot - startOffset)) - , m_expr(expr) - , m_statement(statement) - , m_identIsVarDecl(true) -{ - if (in) { - AssignResolveNode* node = new AssignResolveNode(globalData, ident, in, true); - node->setExceptionSourceCode(divot, divot - startOffset, endOffset - divot); - m_init = node; - } - // for( var foo = bar in baz ) -} - -RegisterID* ForInNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); - - if (!m_lexpr->isLocation()) - return emitThrowError(generator, ReferenceError, "Left side of for-in statement is not a reference."); - - RefPtr<LabelID> continueTarget = generator.newLabel(); - - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - if (m_init) - generator.emitNode(ignoredResult(), m_init.get()); - RegisterID* forInBase = generator.emitNode(m_expr.get()); - RefPtr<RegisterID> iter = generator.emitGetPropertyNames(generator.newTemporary(), forInBase); - generator.emitJump(scope->continueTarget()); - - RefPtr<LabelID> loopStart = generator.newLabel(); - generator.emitLabel(loopStart.get()); - - RegisterID* propertyName; - if (m_lexpr->isResolveNode()) { - const Identifier& ident = static_cast<ResolveNode*>(m_lexpr.get())->identifier(); - propertyName = generator.registerFor(ident); - if (!propertyName) { - propertyName = generator.newTemporary(); - RefPtr<RegisterID> protect = propertyName; - RegisterID* base = generator.emitResolveBase(generator.newTemporary(), ident); - - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - generator.emitPutById(base, ident, propertyName); - } - } else if (m_lexpr->isDotAccessorNode()) { - DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr.get()); - const Identifier& ident = assignNode->identifier(); - propertyName = generator.newTemporary(); - RefPtr<RegisterID> protect = propertyName; - RegisterID* base = generator.emitNode(assignNode->base()); - - generator.emitExpressionInfo(assignNode->divot(), assignNode->startOffset(), assignNode->endOffset()); - generator.emitPutById(base, ident, propertyName); - } else { - ASSERT(m_lexpr->isBracketAccessorNode()); - BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr.get()); - propertyName = generator.newTemporary(); - RefPtr<RegisterID> protect = propertyName; - RefPtr<RegisterID> base = generator.emitNode(assignNode->base()); - RegisterID* subscript = generator.emitNode(assignNode->subscript()); - - generator.emitExpressionInfo(assignNode->divot(), assignNode->startOffset(), assignNode->endOffset()); - generator.emitPutByVal(base.get(), subscript, propertyName); - } - - if (!m_statement->isBlock()) - generator.emitDebugHook(WillExecuteStatement, m_statement->firstLine(), m_statement->lastLine()); - generator.emitNode(dst, m_statement.get()); - - generator.emitLabel(scope->continueTarget()); - generator.emitNextPropertyName(propertyName, iter.get(), loopStart.get()); - generator.emitLabel(scope->breakTarget()); - return dst; -} - -// ------------------------------ ContinueNode --------------------------------- - -// ECMA 12.7 -RegisterID* ContinueNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - LabelScope* scope = generator.continueTarget(m_ident); - - if (!scope) - return m_ident.isEmpty() - ? emitThrowError(generator, SyntaxError, "Invalid continue statement.") - : emitThrowError(generator, SyntaxError, "Undefined label: '%s'.", m_ident); - - generator.emitJumpScopes(scope->continueTarget(), scope->scopeDepth()); - return dst; -} - -// ------------------------------ BreakNode ------------------------------------ - -// ECMA 12.8 -RegisterID* BreakNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - LabelScope* scope = generator.breakTarget(m_ident); - - if (!scope) - return m_ident.isEmpty() - ? emitThrowError(generator, SyntaxError, "Invalid break statement.") - : emitThrowError(generator, SyntaxError, "Undefined label: '%s'.", m_ident); - - generator.emitJumpScopes(scope->breakTarget(), scope->scopeDepth()); - return dst; -} - -// ------------------------------ ReturnNode ----------------------------------- - -RegisterID* ReturnNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - if (generator.codeType() != FunctionCode) - return emitThrowError(generator, SyntaxError, "Invalid return statement."); - - if (dst == ignoredResult()) - dst = 0; - RegisterID* r0 = m_value ? generator.emitNode(dst, m_value.get()) : generator.emitLoad(dst, jsUndefined()); - if (generator.scopeDepth()) { - RefPtr<LabelID> l0 = generator.newLabel(); - generator.emitJumpScopes(l0.get(), 0); - generator.emitLabel(l0.get()); - } - generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine()); - return generator.emitReturn(r0); -} - -// ------------------------------ WithNode ------------------------------------- - -RegisterID* WithNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> scope = generator.emitNode(m_expr.get()); // scope must be protected until popped - generator.emitExpressionInfo(m_divot, m_expressionLength, 0); - generator.emitPushScope(scope.get()); - RegisterID* result = generator.emitNode(dst, m_statement.get()); - generator.emitPopScope(); - return result; -} - -// ------------------------------ CaseBlockNode -------------------------------- -enum SwitchKind { - SwitchUnset = 0, - SwitchNumber = 1, - SwitchString = 2, - SwitchNeither = 3 -}; - -static void processClauseList(ClauseListNode* list, Vector<ExpressionNode*, 8>& literalVector, SwitchKind& typeForTable, bool& singleCharacterSwitch, int32_t& min_num, int32_t& max_num) -{ - for (; list; list = list->getNext()) { - ExpressionNode* clauseExpression = list->getClause()->expr(); - literalVector.append(clauseExpression); - if (clauseExpression->isNumber()) { - double value = static_cast<NumberNode*>(clauseExpression)->value(); - if ((typeForTable & ~SwitchNumber) || !JSImmediate::from(value)) { - typeForTable = SwitchNeither; - break; - } - int32_t intVal = static_cast<int32_t>(value); - ASSERT(intVal == value); - if (intVal < min_num) - min_num = intVal; - if (intVal > max_num) - max_num = intVal; - typeForTable = SwitchNumber; - continue; - } - if (clauseExpression->isString()) { - if (typeForTable & ~SwitchString) { - typeForTable = SwitchNeither; - break; - } - const UString& value = static_cast<StringNode*>(clauseExpression)->value().ustring(); - if (singleCharacterSwitch &= value.size() == 1) { - int32_t intVal = value.rep()->data()[0]; - if (intVal < min_num) - min_num = intVal; - if (intVal > max_num) - max_num = intVal; - } - typeForTable = SwitchString; - continue; - } - typeForTable = SwitchNeither; - break; - } -} - -SwitchInfo::SwitchType CaseBlockNode::tryOptimizedSwitch(Vector<ExpressionNode*, 8>& literalVector, int32_t& min_num, int32_t& max_num) -{ - SwitchKind typeForTable = SwitchUnset; - bool singleCharacterSwitch = true; - - processClauseList(m_list1.get(), literalVector, typeForTable, singleCharacterSwitch, min_num, max_num); - processClauseList(m_list2.get(), literalVector, typeForTable, singleCharacterSwitch, min_num, max_num); - - if (typeForTable == SwitchUnset || typeForTable == SwitchNeither) - return SwitchInfo::SwitchNone; - - if (typeForTable == SwitchNumber) { - int32_t range = max_num - min_num; - if (min_num <= max_num && range <= 1000 && (range / literalVector.size()) < 10) - return SwitchInfo::SwitchImmediate; - return SwitchInfo::SwitchNone; - } - - ASSERT(typeForTable == SwitchString); - - if (singleCharacterSwitch) { - int32_t range = max_num - min_num; - if (min_num <= max_num && range <= 1000 && (range / literalVector.size()) < 10) - return SwitchInfo::SwitchCharacter; - } - - return SwitchInfo::SwitchString; -} - -RegisterID* CaseBlockNode::emitCodeForBlock(CodeGenerator& generator, RegisterID* switchExpression, RegisterID* dst) -{ - RefPtr<LabelID> defaultLabel; - Vector<RefPtr<LabelID>, 8> labelVector; - Vector<ExpressionNode*, 8> literalVector; - int32_t min_num = std::numeric_limits<int32_t>::max(); - int32_t max_num = std::numeric_limits<int32_t>::min(); - SwitchInfo::SwitchType switchType = tryOptimizedSwitch(literalVector, min_num, max_num); - - if (switchType != SwitchInfo::SwitchNone) { - // Prepare the various labels - for (uint32_t i = 0; i < literalVector.size(); i++) - labelVector.append(generator.newLabel()); - defaultLabel = generator.newLabel(); - generator.beginSwitch(switchExpression, switchType); - } else { - // Setup jumps - for (ClauseListNode* list = m_list1.get(); list; list = list->getNext()) { - RefPtr<RegisterID> clauseVal = generator.newTemporary(); - generator.emitNode(clauseVal.get(), list->getClause()->expr()); - generator.emitBinaryOp(op_stricteq, clauseVal.get(), clauseVal.get(), switchExpression, OperandTypes()); - labelVector.append(generator.newLabel()); - generator.emitJumpIfTrue(clauseVal.get(), labelVector[labelVector.size() - 1].get()); - } - - for (ClauseListNode* list = m_list2.get(); list; list = list->getNext()) { - RefPtr<RegisterID> clauseVal = generator.newTemporary(); - generator.emitNode(clauseVal.get(), list->getClause()->expr()); - generator.emitBinaryOp(op_stricteq, clauseVal.get(), clauseVal.get(), switchExpression, OperandTypes()); - labelVector.append(generator.newLabel()); - generator.emitJumpIfTrue(clauseVal.get(), labelVector[labelVector.size() - 1].get()); - } - defaultLabel = generator.newLabel(); - generator.emitJump(defaultLabel.get()); - } - - RegisterID* result = 0; - - size_t i = 0; - for (ClauseListNode* list = m_list1.get(); list; list = list->getNext()) { - generator.emitLabel(labelVector[i++].get()); - result = statementListEmitCode(list->getClause()->children(), generator, dst); - } - - if (m_defaultClause) { - generator.emitLabel(defaultLabel.get()); - result = statementListEmitCode(m_defaultClause->children(), generator, dst); - } - - for (ClauseListNode* list = m_list2.get(); list; list = list->getNext()) { - generator.emitLabel(labelVector[i++].get()); - result = statementListEmitCode(list->getClause()->children(), generator, dst); - } - if (!m_defaultClause) - generator.emitLabel(defaultLabel.get()); - - ASSERT(i == labelVector.size()); - if (switchType != SwitchInfo::SwitchNone) { - ASSERT(labelVector.size() == literalVector.size()); - generator.endSwitch(labelVector.size(), labelVector.data(), literalVector.data(), defaultLabel.get(), min_num, max_num); - } - return result; -} - -// ------------------------------ SwitchNode ----------------------------------- - -RegisterID* SwitchNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Switch); - - RefPtr<RegisterID> r0 = generator.emitNode(m_expr.get()); - RegisterID* r1 = m_block->emitCodeForBlock(generator, r0.get(), dst); - - generator.emitLabel(scope->breakTarget()); - return r1; -} - -// ------------------------------ LabelNode ------------------------------------ - -RegisterID* LabelNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - if (generator.breakTarget(m_name)) - return emitThrowError(generator, SyntaxError, "Duplicate label: %s.", m_name); - - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::NamedLabel, &m_name); - RegisterID* r0 = generator.emitNode(dst, m_statement.get()); - - generator.emitLabel(scope->breakTarget()); - return r0; -} - -// ------------------------------ ThrowNode ------------------------------------ - -RegisterID* ThrowNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - if (dst == ignoredResult()) - dst = 0; - RefPtr<RegisterID> expr = generator.emitNode(dst, m_expr.get()); - generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset); - generator.emitThrow(expr.get()); - return dst; -} - -// ------------------------------ TryNode -------------------------------------- - -RegisterID* TryNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - RefPtr<LabelID> tryStartLabel = generator.newLabel(); - RefPtr<LabelID> tryEndLabel = generator.newLabel(); - RefPtr<LabelID> finallyStart; - RefPtr<RegisterID> finallyReturnAddr; - if (m_finallyBlock) { - finallyStart = generator.newLabel(); - finallyReturnAddr = generator.newTemporary(); - generator.pushFinallyContext(finallyStart.get(), finallyReturnAddr.get()); - } - generator.emitLabel(tryStartLabel.get()); - generator.emitNode(dst, m_tryBlock.get()); - generator.emitLabel(tryEndLabel.get()); - - if (m_catchBlock) { - RefPtr<LabelID> handlerEndLabel = generator.newLabel(); - generator.emitJump(handlerEndLabel.get()); - RefPtr<RegisterID> exceptionRegister = generator.emitCatch(generator.newTemporary(), tryStartLabel.get(), tryEndLabel.get()); - generator.emitPushNewScope(exceptionRegister.get(), m_exceptionIdent, exceptionRegister.get()); - generator.emitNode(dst, m_catchBlock.get()); - generator.emitPopScope(); - generator.emitLabel(handlerEndLabel.get()); - } - - if (m_finallyBlock) { - generator.popFinallyContext(); - // there may be important registers live at the time we jump - // to a finally block (such as for a return or throw) so we - // ref the highest register ever used as a conservative - // approach to not clobbering anything important - RefPtr<RegisterID> highestUsedRegister = generator.highestUsedRegister(); - RefPtr<LabelID> finallyEndLabel = generator.newLabel(); - generator.emitJumpSubroutine(finallyReturnAddr.get(), finallyStart.get()); - // Use a label to record the subtle fact that sret will return to the - // next instruction. sret is the only way to jump without an explicit label. - generator.emitLabel(generator.newLabel().get()); - generator.emitJump(finallyEndLabel.get()); - - // Finally block for exception path - RefPtr<RegisterID> tempExceptionRegister = generator.emitCatch(generator.newTemporary(), tryStartLabel.get(), generator.emitLabel(generator.newLabel().get()).get()); - generator.emitJumpSubroutine(finallyReturnAddr.get(), finallyStart.get()); - // Use a label to record the subtle fact that sret will return to the - // next instruction. sret is the only way to jump without an explicit label. - generator.emitLabel(generator.newLabel().get()); - generator.emitThrow(tempExceptionRegister.get()); - - // emit the finally block itself - generator.emitLabel(finallyStart.get()); - generator.emitNode(dst, m_finallyBlock.get()); - generator.emitSubroutineReturn(finallyReturnAddr.get()); - - generator.emitLabel(finallyEndLabel.get()); - } - - return dst; -} - - -// ------------------------------ ScopeNode ----------------------------- - -ScopeNode::ScopeNode(JSGlobalData* globalData, const SourceCode& source, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, CodeFeatures features, int numConstants) - : BlockNode(globalData, children) - , m_source(source) - , m_features(features) - , m_numConstants(numConstants) -{ - if (varStack) - m_varStack = *varStack; - if (funcStack) - m_functionStack = *funcStack; -#if ENABLE(OPCODE_SAMPLING) - globalData->machine->sampler()->notifyOfScope(this); -#endif -} - -// ------------------------------ ProgramNode ----------------------------- - -ProgramNode::ProgramNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants) - : ScopeNode(globalData, source, children, varStack, funcStack, features, numConstants) -{ -} - -ProgramNode* ProgramNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants) -{ - return new ProgramNode(globalData, children, varStack, funcStack, source, features, numConstants); -} - -// ------------------------------ EvalNode ----------------------------- - -EvalNode::EvalNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants) - : ScopeNode(globalData, source, children, varStack, funcStack, features, numConstants) -{ -} - -RegisterID* EvalNode::emitCode(CodeGenerator& generator, RegisterID*) -{ - generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine()); - - RefPtr<RegisterID> dstRegister = generator.newTemporary(); - generator.emitLoad(dstRegister.get(), jsUndefined()); - statementListEmitCode(m_children, generator, dstRegister.get()); - - generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine()); - generator.emitEnd(dstRegister.get()); - return 0; -} - -void EvalNode::generateCode(ScopeChainNode* scopeChainNode) -{ - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); - - SymbolTable symbolTable; - m_code.set(new EvalCodeBlock(this, globalObject, source().provider())); - - CodeGenerator generator(this, globalObject->debugger(), scopeChain, &symbolTable, m_code.get()); - generator.generate(); -} - -EvalNode* EvalNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants) -{ - return new EvalNode(globalData, children, varStack, funcStack, source, features, numConstants); -} - -// ------------------------------ FunctionBodyNode ----------------------------- - -FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& sourceCode, CodeFeatures features, int numConstants) - : ScopeNode(globalData, sourceCode, children, varStack, funcStack, features, numConstants) - , m_parameters(0) - , m_parameterCount(0) - , m_refCount(0) -{ -} - -FunctionBodyNode::~FunctionBodyNode() -{ - if (m_parameters) - fastFree(m_parameters); -} - -void FunctionBodyNode::finishParsing(const SourceCode& source, ParameterNode* firstParameter) -{ - Vector<Identifier> parameters; - for (ParameterNode* parameter = firstParameter; parameter; parameter = parameter->nextParam()) - parameters.append(parameter->ident()); - size_t count = parameters.size(); - - setSource(source); - finishParsing(parameters.releaseBuffer(), count); -} - -void FunctionBodyNode::finishParsing(Identifier* parameters, size_t parameterCount) -{ - ASSERT(!source().isNull()); - m_parameters = parameters; - m_parameterCount = parameterCount; -} - -void FunctionBodyNode::mark() -{ - if (m_code) - m_code->mark(); -} - -FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, CodeFeatures features, int numConstants) -{ - return new FunctionBodyNode(globalData, children, varStack, funcStack, SourceCode(), features, numConstants); -} - -FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& sourceCode, CodeFeatures features, int numConstants) -{ - return new FunctionBodyNode(globalData, children, varStack, funcStack, sourceCode, features, numConstants); -} - -void FunctionBodyNode::generateCode(ScopeChainNode* scopeChainNode) -{ - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); - - m_code.set(new CodeBlock(this, FunctionCode, source().provider(), source().startOffset())); - - CodeGenerator generator(this, globalObject->debugger(), scopeChain, &m_symbolTable, m_code.get()); - generator.generate(); -} - -RegisterID* FunctionBodyNode::emitCode(CodeGenerator& generator, RegisterID*) -{ - generator.emitDebugHook(DidEnterCallFrame, firstLine(), lastLine()); - statementListEmitCode(m_children, generator, ignoredResult()); - if (!m_children.size() || !m_children.last()->isReturnNode()) { - RegisterID* r0 = generator.emitLoad(0, jsUndefined()); - generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine()); - generator.emitReturn(r0); - } - return 0; -} - -RegisterID* ProgramNode::emitCode(CodeGenerator& generator, RegisterID*) -{ - generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine()); - - RefPtr<RegisterID> dstRegister = generator.newTemporary(); - generator.emitLoad(dstRegister.get(), jsUndefined()); - statementListEmitCode(m_children, generator, dstRegister.get()); - - generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine()); - generator.emitEnd(dstRegister.get()); - return 0; -} - -void ProgramNode::generateCode(ScopeChainNode* scopeChainNode) -{ - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); - - m_code.set(new ProgramCodeBlock(this, GlobalCode, globalObject, source().provider())); - - CodeGenerator generator(this, globalObject->debugger(), scopeChain, &globalObject->symbolTable(), m_code.get(), m_varStack, m_functionStack); - generator.generate(); -} - -UString FunctionBodyNode::paramString() const -{ - UString s(""); - for (size_t pos = 0; pos < m_parameterCount; ++pos) { - if (!s.isEmpty()) - s += ", "; - s += parameters()[pos].ustring(); - } - - return s; -} - -Identifier* FunctionBodyNode::copyParameters() -{ - Identifier* parameters = static_cast<Identifier*>(fastMalloc(m_parameterCount * sizeof(Identifier))); - VectorCopier<false, Identifier>::uninitializedCopy(m_parameters, m_parameters + m_parameterCount, parameters); - return parameters; -} - -// ------------------------------ FuncDeclNode --------------------------------- - -JSFunction* FuncDeclNode::makeFunction(ExecState* exec, ScopeChainNode* scopeChain) -{ - return new (exec) JSFunction(exec, m_ident, m_body.get(), scopeChain); -} - -RegisterID* FuncDeclNode::emitCode(CodeGenerator&, RegisterID* dst) -{ - return dst; -} - -// ------------------------------ FuncExprNode --------------------------------- - -RegisterID* FuncExprNode::emitCode(CodeGenerator& generator, RegisterID* dst) -{ - return generator.emitNewFunctionExpression(generator.finalDestination(dst), this); -} - -JSFunction* FuncExprNode::makeFunction(ExecState* exec, ScopeChainNode* scopeChain) -{ - JSFunction* func = new (exec) JSFunction(exec, m_ident, m_body.get(), scopeChain); - - /* - The Identifier in a FunctionExpression can be referenced from inside - the FunctionExpression's FunctionBody to allow the function to call - itself recursively. However, unlike in a FunctionDeclaration, the - Identifier in a FunctionExpression cannot be referenced from and - does not affect the scope enclosing the FunctionExpression. - */ - - if (!m_ident.isNull()) { - JSStaticScopeObject* functionScopeObject = new (exec) JSStaticScopeObject(exec, m_ident, func, ReadOnly | DontDelete); - func->scope().push(functionScopeObject); - } - - return func; -} - -} // namespace JSC diff --git a/JavaScriptCore/kjs/nodes.h b/JavaScriptCore/kjs/nodes.h deleted file mode 100644 index a70d350..0000000 --- a/JavaScriptCore/kjs/nodes.h +++ /dev/null @@ -1,2493 +0,0 @@ -/* - * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) - * Copyright (C) 2007 Maks Orlovich - * Copyright (C) 2007 Eric Seidel <eric@webkit.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#ifndef NODES_H_ -#define NODES_H_ - -#include "Error.h" -#include "JSString.h" -#include "JSType.h" -#include "Opcode.h" -#include "RegisterID.h" -#include "ResultType.h" -#include "SourceCode.h" -#include "SymbolTable.h" -#include "regexp.h" -#include <wtf/ListRefPtr.h> -#include <wtf/MathExtras.h> -#include <wtf/OwnPtr.h> -#include <wtf/UnusedParam.h> -#include <wtf/Vector.h> - -#if PLATFORM(X86) && COMPILER(GCC) -#define JSC_FAST_CALL __attribute__((regparm(3))) -#else -#define JSC_FAST_CALL -#endif - -namespace JSC { - - class CodeBlock; - class CodeGenerator; - class FuncDeclNode; - class Node; - class EvalCodeBlock; - class JSFunction; - class ProgramCodeBlock; - class PropertyListNode; - class SourceStream; - - typedef unsigned int CodeFeatures; - - const CodeFeatures NoFeatures = 0; - const CodeFeatures EvalFeature = 1 << 0; - const CodeFeatures ClosureFeature = 1 << 1; - const CodeFeatures AssignFeature = 1 << 2; - const CodeFeatures ArgumentsFeature = 1 << 3; - const CodeFeatures WithFeature = 1 << 4; - const CodeFeatures CatchFeature = 1 << 5; - const CodeFeatures ThisFeature = 1 << 6; - const CodeFeatures AllFeatures = EvalFeature | ClosureFeature | AssignFeature | ArgumentsFeature | WithFeature | CatchFeature | ThisFeature; - - enum Operator { - OpEqual, - OpPlusEq, - OpMinusEq, - OpMultEq, - OpDivEq, - OpPlusPlus, - OpMinusMinus, - OpAndEq, - OpXOrEq, - OpOrEq, - OpModEq, - OpLShift, - OpRShift, - OpURShift - }; - - enum LogicalOperator { - OpLogicalAnd, - OpLogicalOr - }; - - enum Precedence { - PrecPrimary, - PrecMember, - PrecCall, - PrecLeftHandSide, - PrecPostfix, - PrecUnary, - PrecMultiplicative, - PrecAdditive, - PrecShift, - PrecRelational, - PrecEquality, - PrecBitwiseAnd, - PrecBitwiseXor, - PrecBitwiseOr, - PrecLogicalAnd, - PrecLogicalOr, - PrecConditional, - PrecAssignment, - PrecExpression - }; - - namespace DeclarationStacks { - typedef Vector<Node*, 16> NodeStack; - enum VarAttrs { IsConstant = 1, HasInitializer = 2 }; - typedef Vector<std::pair<Identifier, unsigned>, 16> VarStack; - typedef Vector<RefPtr<FuncDeclNode>, 16> FunctionStack; - } - - struct SwitchInfo { - enum SwitchType { SwitchNone, SwitchImmediate, SwitchCharacter, SwitchString }; - uint32_t opcodeOffset; - SwitchType switchType; - }; - - class ParserRefCounted : Noncopyable { - protected: - ParserRefCounted(JSGlobalData*) JSC_FAST_CALL; - - JSGlobalData* m_globalData; - - public: - void ref() JSC_FAST_CALL; - void deref() JSC_FAST_CALL; - bool hasOneRef() JSC_FAST_CALL; - - static void deleteNewObjects(JSGlobalData*) JSC_FAST_CALL; - - virtual ~ParserRefCounted(); - }; - - class Node : public ParserRefCounted { - public: - typedef DeclarationStacks::NodeStack NodeStack; - typedef DeclarationStacks::VarStack VarStack; - typedef DeclarationStacks::FunctionStack FunctionStack; - - Node(JSGlobalData*) JSC_FAST_CALL; - - /* - Return value: The register holding the production's value. - dst: An optional parameter specifying the most efficient - destination at which to store the production's value. - The callee must honor dst. - - dst provides for a crude form of copy propagation. For example, - - x = 1 - - becomes - - load r[x], 1 - - instead of - - load r0, 1 - mov r[x], r0 - - because the assignment node, "x =", passes r[x] as dst to the number - node, "1". - */ - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* dst = 0) JSC_FAST_CALL - { - ASSERT_WITH_MESSAGE(0, "Don't know how to generate code for:\n%s\n", toString().ascii()); - UNUSED_PARAM(dst); - return 0; - } // FIXME: Make this pure virtual. - - UString toString() const JSC_FAST_CALL; - int lineNo() const { return m_line; } - - virtual bool isReturnNode() const JSC_FAST_CALL { return false; } - - // Serialization. - virtual void streamTo(SourceStream&) const JSC_FAST_CALL = 0; - virtual Precedence precedence() const = 0; - virtual bool needsParensIfLeftmost() const { return false; } - - protected: - int m_line; - }; - - class ExpressionNode : public Node { - public: - ExpressionNode(JSGlobalData* globalData, ResultType resultDesc = ResultType::unknown()) JSC_FAST_CALL - : Node(globalData) - , m_resultDesc(resultDesc) - { - } - - virtual bool isNumber() const JSC_FAST_CALL { return false; } - virtual bool isString() const JSC_FAST_CALL { return false; } - virtual bool isNull() const JSC_FAST_CALL { return false; } - virtual bool isPure(CodeGenerator&) const JSC_FAST_CALL { return false; } - virtual bool isLocation() const JSC_FAST_CALL { return false; } - virtual bool isResolveNode() const JSC_FAST_CALL { return false; } - virtual bool isBracketAccessorNode() const JSC_FAST_CALL { return false; } - virtual bool isDotAccessorNode() const JSC_FAST_CALL { return false; } - - virtual ExpressionNode* stripUnaryPlus() { return this; } - - ResultType resultDescriptor() const JSC_FAST_CALL { return m_resultDesc; } - - // This needs to be in public in order to compile using GCC 3.x - typedef enum { EvalOperator, FunctionCall } CallerType; - - private: - ResultType m_resultDesc; - }; - - class StatementNode : public Node { - public: - StatementNode(JSGlobalData*) JSC_FAST_CALL; - void setLoc(int line0, int line1) JSC_FAST_CALL; - int firstLine() const JSC_FAST_CALL { return lineNo(); } - int lastLine() const JSC_FAST_CALL { return m_lastLine; } - - virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; } - virtual bool isEmptyStatement() const JSC_FAST_CALL { return false; } - - virtual bool isBlock() const JSC_FAST_CALL { return false; } - virtual bool isLoop() const JSC_FAST_CALL { return false; } - - private: - int m_lastLine; - }; - - class NullNode : public ExpressionNode { - public: - NullNode(JSGlobalData* globalData) JSC_FAST_CALL - : ExpressionNode(globalData, ResultType::nullType()) - { - } - - virtual bool isNull() const JSC_FAST_CALL { return true; } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecPrimary; } - }; - - class BooleanNode : public ExpressionNode { - public: - BooleanNode(JSGlobalData* globalData, bool value) JSC_FAST_CALL - : ExpressionNode(globalData, ResultType::boolean()) - , m_value(value) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual bool isPure(CodeGenerator&) const JSC_FAST_CALL { return true; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecPrimary; } - - protected: - bool m_value; - }; - - class NumberNode : public ExpressionNode { - public: - NumberNode(JSGlobalData* globalData, double v) JSC_FAST_CALL - : ExpressionNode(globalData, ResultType::constNumber()) - , m_double(v) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return signbit(m_double) ? PrecUnary : PrecPrimary; } - - virtual bool isNumber() const JSC_FAST_CALL { return true; } - virtual bool isPure(CodeGenerator&) const JSC_FAST_CALL { return true; } - double value() const JSC_FAST_CALL { return m_double; } - virtual void setValue(double d) JSC_FAST_CALL { m_double = d; } - - protected: - double m_double; - }; - - class ImmediateNumberNode : public NumberNode { - public: - ImmediateNumberNode(JSGlobalData* globalData, JSValue* v, double d) JSC_FAST_CALL - : NumberNode(globalData, d) - , m_value(v) - { - ASSERT(v == JSImmediate::from(d)); - } - - virtual void setValue(double d) JSC_FAST_CALL { m_double = d; m_value = JSImmediate::from(d); ASSERT(m_value); } - - private: - JSValue* m_value; // This is never a JSCell, only JSImmediate, thus no ProtectedPtr - }; - - class StringNode : public ExpressionNode { - public: - StringNode(JSGlobalData* globalData, const Identifier& v) JSC_FAST_CALL - : ExpressionNode(globalData, ResultType::string()) - , m_value(v) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual bool isString() const JSC_FAST_CALL { return true; } - const Identifier& value() { return m_value; } - virtual bool isPure(CodeGenerator&) const JSC_FAST_CALL { return true; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecPrimary; } - - private: - Identifier m_value; - }; - - class ThrowableExpressionData { - public: - ThrowableExpressionData() - : m_divot(static_cast<uint32_t>(-1)) - , m_startOffset(static_cast<uint16_t>(-1)) - , m_endOffset(static_cast<uint16_t>(-1)) - { - } - - ThrowableExpressionData(unsigned divot, unsigned startOffset, unsigned endOffset) - : m_divot(divot) - , m_startOffset(startOffset) - , m_endOffset(endOffset) - { - } - - void setExceptionSourceCode(unsigned divot, unsigned startOffset, unsigned endOffset) - { - m_divot = divot; - m_startOffset = startOffset; - m_endOffset = endOffset; - } - - uint32_t divot() const { return m_divot; } - uint16_t startOffset() const { return m_startOffset; } - uint16_t endOffset() const { return m_endOffset; } - - protected: - RegisterID* emitThrowError(CodeGenerator&, ErrorType, const char* msg); - RegisterID* emitThrowError(CodeGenerator&, ErrorType, const char* msg, const Identifier&); - uint32_t m_divot; - uint16_t m_startOffset; - uint16_t m_endOffset; - }; - - class ThrowableSubExpressionData : public ThrowableExpressionData { - public: - ThrowableSubExpressionData() - : ThrowableExpressionData() - , m_subexpressionDivotOffset(0) - , m_subexpressionEndOffset(0) - { - } - - ThrowableSubExpressionData(unsigned divot, unsigned startOffset, unsigned endOffset) - : ThrowableExpressionData(divot, startOffset, endOffset) - , m_subexpressionDivotOffset(0) - , m_subexpressionEndOffset(0) - { - } - - void setSubexpressionInfo(uint32_t subexpressionDivot, uint16_t subexpressionOffset) { - ASSERT(subexpressionDivot <= m_divot); - if ((m_divot - subexpressionDivot) & ~0xFFFF) // Overflow means we can't do this safely, so just point at the primary divot - return; - m_subexpressionDivotOffset = m_divot - subexpressionDivot; - m_subexpressionEndOffset = subexpressionOffset; - } - - protected: - uint16_t m_subexpressionDivotOffset; - uint16_t m_subexpressionEndOffset; - }; - - class ThrowablePrefixedSubExpressionData : public ThrowableExpressionData { - public: - ThrowablePrefixedSubExpressionData() - : ThrowableExpressionData() - , m_subexpressionDivotOffset(0) - , m_subexpressionStartOffset(0) - { - } - - ThrowablePrefixedSubExpressionData(unsigned divot, unsigned startOffset, unsigned endOffset) - : ThrowableExpressionData(divot, startOffset, endOffset) - , m_subexpressionDivotOffset(0) - , m_subexpressionStartOffset(0) - { - } - - void setSubexpressionInfo(uint32_t subexpressionDivot, uint16_t subexpressionOffset) { - ASSERT(subexpressionDivot >= m_divot); - if ((subexpressionDivot - m_divot) & ~0xFFFF) // Overflow means we can't do this safely, so just point at the primary divot - return; - m_subexpressionDivotOffset = subexpressionDivot - m_divot; - m_subexpressionStartOffset = subexpressionOffset; - } - - protected: - uint16_t m_subexpressionDivotOffset; - uint16_t m_subexpressionStartOffset; - }; - - class RegExpNode : public ExpressionNode, public ThrowableExpressionData { - public: - RegExpNode(JSGlobalData* globalData, const UString& pattern, const UString& flags) JSC_FAST_CALL - : ExpressionNode(globalData) - , m_pattern(pattern) - , m_flags(flags) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecPrimary; } - - private: - UString m_pattern; - UString m_flags; - }; - - class ThisNode : public ExpressionNode { - public: - ThisNode(JSGlobalData* globalData) JSC_FAST_CALL - : ExpressionNode(globalData) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecPrimary; } - }; - - class ResolveNode : public ExpressionNode { - public: - ResolveNode(JSGlobalData* globalData, const Identifier& ident, int startOffset) JSC_FAST_CALL - : ExpressionNode(globalData) - , m_ident(ident) - , m_startOffset(startOffset) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecPrimary; } - - virtual bool isPure(CodeGenerator&) const JSC_FAST_CALL; - virtual bool isLocation() const JSC_FAST_CALL { return true; } - virtual bool isResolveNode() const JSC_FAST_CALL { return true; } - const Identifier& identifier() const JSC_FAST_CALL { return m_ident; } - - protected: - Identifier m_ident; - int32_t m_startOffset; - - }; - - class ElementNode : public Node { - public: - ElementNode(JSGlobalData* globalData, int elision, ExpressionNode* node) JSC_FAST_CALL - : Node(globalData) - , m_elision(elision) - , m_node(node) - { - } - - ElementNode(JSGlobalData* globalData, ElementNode* l, int elision, ExpressionNode* node) JSC_FAST_CALL - : Node(globalData) - , m_elision(elision) - , m_node(node) - { - l->m_next = this; - } - - virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - - int elision() const { return m_elision; } - ExpressionNode* value() { return m_node.get(); } - - ElementNode* next() { return m_next.get(); } - PassRefPtr<ElementNode> releaseNext() JSC_FAST_CALL { return m_next.release(); } - - private: - ListRefPtr<ElementNode> m_next; - int m_elision; - RefPtr<ExpressionNode> m_node; - }; - - class ArrayNode : public ExpressionNode { - public: - ArrayNode(JSGlobalData* globalData, int elision) JSC_FAST_CALL - : ExpressionNode(globalData) - , m_elision(elision) - , m_optional(true) - { - } - - ArrayNode(JSGlobalData* globalData, ElementNode* element) JSC_FAST_CALL - : ExpressionNode(globalData) - , m_element(element) - , m_elision(0) - , m_optional(false) - { - } - - ArrayNode(JSGlobalData* globalData, int elision, ElementNode* element) JSC_FAST_CALL - : ExpressionNode(globalData) - , m_element(element) - , m_elision(elision) - , m_optional(true) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecPrimary; } - - private: - RefPtr<ElementNode> m_element; - int m_elision; - bool m_optional; - }; - - class PropertyNode : public Node { - public: - enum Type { Constant, Getter, Setter }; - - PropertyNode(JSGlobalData* globalData, const Identifier& name, ExpressionNode* assign, Type type) JSC_FAST_CALL - : Node(globalData) - , m_name(name) - , m_assign(assign) - , m_type(type) - { - } - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; } - - const Identifier& name() const { return m_name; } - - private: - friend class PropertyListNode; - Identifier m_name; - RefPtr<ExpressionNode> m_assign; - Type m_type; - }; - - class PropertyListNode : public Node { - public: - PropertyListNode(JSGlobalData* globalData, PropertyNode* node) JSC_FAST_CALL - : Node(globalData) - , m_node(node) - { - } - - PropertyListNode(JSGlobalData* globalData, PropertyNode* node, PropertyListNode* list) JSC_FAST_CALL - : Node(globalData) - , m_node(node) - { - list->m_next = this; - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; } - - PassRefPtr<PropertyListNode> releaseNext() JSC_FAST_CALL { return m_next.release(); } - - private: - friend class ObjectLiteralNode; - RefPtr<PropertyNode> m_node; - ListRefPtr<PropertyListNode> m_next; - }; - - class ObjectLiteralNode : public ExpressionNode { - public: - ObjectLiteralNode(JSGlobalData* globalData) JSC_FAST_CALL - : ExpressionNode(globalData) - { - } - - ObjectLiteralNode(JSGlobalData* globalData, PropertyListNode* list) JSC_FAST_CALL - : ExpressionNode(globalData) - , m_list(list) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecPrimary; } - virtual bool needsParensIfLeftmost() const { return true; } - - private: - RefPtr<PropertyListNode> m_list; - }; - - class BracketAccessorNode : public ExpressionNode, public ThrowableExpressionData { - public: - BracketAccessorNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, bool subscriptHasAssignments) JSC_FAST_CALL - : ExpressionNode(globalData) - , m_base(base) - , m_subscript(subscript) - , m_subscriptHasAssignments(subscriptHasAssignments) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecMember; } - - virtual bool isLocation() const JSC_FAST_CALL { return true; } - virtual bool isBracketAccessorNode() const JSC_FAST_CALL { return true; } - ExpressionNode* base() JSC_FAST_CALL { return m_base.get(); } - ExpressionNode* subscript() JSC_FAST_CALL { return m_subscript.get(); } - - private: - RefPtr<ExpressionNode> m_base; - RefPtr<ExpressionNode> m_subscript; - bool m_subscriptHasAssignments; - }; - - class DotAccessorNode : public ExpressionNode, public ThrowableExpressionData { - public: - DotAccessorNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident) JSC_FAST_CALL - : ExpressionNode(globalData) - , m_base(base) - , m_ident(ident) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecMember; } - - virtual bool isLocation() const JSC_FAST_CALL { return true; } - virtual bool isDotAccessorNode() const JSC_FAST_CALL { return true; } - ExpressionNode* base() const JSC_FAST_CALL { return m_base.get(); } - const Identifier& identifier() const JSC_FAST_CALL { return m_ident; } - - private: - RefPtr<ExpressionNode> m_base; - Identifier m_ident; - }; - - class ArgumentListNode : public Node { - public: - ArgumentListNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL - : Node(globalData) - , m_expr(expr) - { - } - - ArgumentListNode(JSGlobalData* globalData, ArgumentListNode* listNode, ExpressionNode* expr) JSC_FAST_CALL - : Node(globalData) - , m_expr(expr) - { - listNode->m_next = this; - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; } - - PassRefPtr<ArgumentListNode> releaseNext() JSC_FAST_CALL { return m_next.release(); } - - ListRefPtr<ArgumentListNode> m_next; - RefPtr<ExpressionNode> m_expr; - }; - - class ArgumentsNode : public Node { - public: - ArgumentsNode(JSGlobalData* globalData) JSC_FAST_CALL - : Node(globalData) - { - } - - ArgumentsNode(JSGlobalData* globalData, ArgumentListNode* listNode) JSC_FAST_CALL - : Node(globalData) - , m_listNode(listNode) - { - } - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; } - - RefPtr<ArgumentListNode> m_listNode; - }; - - class NewExprNode : public ExpressionNode, public ThrowableExpressionData { - public: - NewExprNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL - : ExpressionNode(globalData) - , m_expr(expr) - { - } - - NewExprNode(JSGlobalData* globalData, ExpressionNode* expr, ArgumentsNode* args) JSC_FAST_CALL - : ExpressionNode(globalData) - , m_expr(expr) - , m_args(args) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecLeftHandSide; } - - private: - RefPtr<ExpressionNode> m_expr; - RefPtr<ArgumentsNode> m_args; - }; - - class EvalFunctionCallNode : public ExpressionNode, public ThrowableExpressionData { - public: - EvalFunctionCallNode(JSGlobalData* globalData, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL - : ExpressionNode(globalData) - , ThrowableExpressionData(divot, startOffset, endOffset) - , m_args(args) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecCall; } - - private: - RefPtr<ArgumentsNode> m_args; - }; - - class FunctionCallValueNode : public ExpressionNode, public ThrowableExpressionData { - public: - FunctionCallValueNode(JSGlobalData* globalData, ExpressionNode* expr, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL - : ExpressionNode(globalData) - , ThrowableExpressionData(divot, startOffset, endOffset) - , m_expr(expr) - , m_args(args) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecCall; } - - private: - RefPtr<ExpressionNode> m_expr; - RefPtr<ArgumentsNode> m_args; - }; - - class FunctionCallResolveNode : public ExpressionNode, public ThrowableExpressionData { - public: - FunctionCallResolveNode(JSGlobalData* globalData, const Identifier& ident, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL - : ExpressionNode(globalData) - , ThrowableExpressionData(divot, startOffset, endOffset) - , m_ident(ident) - , m_args(args) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecCall; } - - protected: - Identifier m_ident; - RefPtr<ArgumentsNode> m_args; - size_t m_index; // Used by LocalVarFunctionCallNode. - size_t m_scopeDepth; // Used by ScopedVarFunctionCallNode and NonLocalVarFunctionCallNode - }; - - class FunctionCallBracketNode : public ExpressionNode, public ThrowableSubExpressionData { - public: - FunctionCallBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL - : ExpressionNode(globalData) - , ThrowableSubExpressionData(divot, startOffset, endOffset) - , m_base(base) - , m_subscript(subscript) - , m_args(args) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecCall; } - - protected: - RefPtr<ExpressionNode> m_base; - RefPtr<ExpressionNode> m_subscript; - RefPtr<ArgumentsNode> m_args; - }; - - class FunctionCallDotNode : public ExpressionNode, public ThrowableSubExpressionData { - public: - FunctionCallDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL - : ExpressionNode(globalData) - , ThrowableSubExpressionData(divot, startOffset, endOffset) - , m_base(base) - , m_ident(ident) - , m_args(args) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecCall; } - - private: - RefPtr<ExpressionNode> m_base; - Identifier m_ident; - RefPtr<ArgumentsNode> m_args; - }; - - class PrePostResolveNode : public ExpressionNode, public ThrowableExpressionData { - public: - PrePostResolveNode(JSGlobalData* globalData, const Identifier& ident, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL - : ExpressionNode(globalData, ResultType::constNumber()) // could be reusable for pre? - , ThrowableExpressionData(divot, startOffset, endOffset) - , m_ident(ident) - { - } - - protected: - Identifier m_ident; - }; - - class PostfixResolveNode : public PrePostResolveNode { - public: - PostfixResolveNode(JSGlobalData* globalData, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL - : PrePostResolveNode(globalData, ident, divot, startOffset, endOffset) - , m_operator(oper) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecPostfix; } - - protected: - Operator m_operator; - }; - - class PostfixBracketNode : public ExpressionNode, public ThrowableSubExpressionData { - public: - PostfixBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL - : ExpressionNode(globalData) - , ThrowableSubExpressionData(divot, startOffset, endOffset) - , m_base(base) - , m_subscript(subscript) - , m_operator(oper) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecPostfix; } - - protected: - RefPtr<ExpressionNode> m_base; - RefPtr<ExpressionNode> m_subscript; - Operator m_operator; - }; - - class PostfixDotNode : public ExpressionNode, public ThrowableSubExpressionData { - public: - PostfixDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL - : ExpressionNode(globalData) - , ThrowableSubExpressionData(divot, startOffset, endOffset) - , m_base(base) - , m_ident(ident) - , m_operator(oper) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecPostfix; } - - protected: - RefPtr<ExpressionNode> m_base; - Identifier m_ident; - Operator m_operator; - }; - - class PostfixErrorNode : public ExpressionNode, public ThrowableSubExpressionData { - public: - PostfixErrorNode(JSGlobalData* globalData, ExpressionNode* expr, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL - : ExpressionNode(globalData) - , ThrowableSubExpressionData(divot, startOffset, endOffset) - , m_expr(expr) - , m_operator(oper) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecPostfix; } - - private: - RefPtr<ExpressionNode> m_expr; - Operator m_operator; - }; - - class DeleteResolveNode : public ExpressionNode, public ThrowableExpressionData { - public: - DeleteResolveNode(JSGlobalData* globalData, const Identifier& ident, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL - : ExpressionNode(globalData) - , ThrowableExpressionData(divot, startOffset, endOffset) - , m_ident(ident) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecUnary; } - - private: - Identifier m_ident; - }; - - class DeleteBracketNode : public ExpressionNode, public ThrowableExpressionData { - public: - DeleteBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL - : ExpressionNode(globalData) - , ThrowableExpressionData(divot, startOffset, endOffset) - , m_base(base) - , m_subscript(subscript) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecUnary; } - - private: - RefPtr<ExpressionNode> m_base; - RefPtr<ExpressionNode> m_subscript; - }; - - class DeleteDotNode : public ExpressionNode, public ThrowableExpressionData { - public: - DeleteDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL - : ExpressionNode(globalData) - , ThrowableExpressionData(divot, startOffset, endOffset) - , m_base(base) - , m_ident(ident) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecUnary; } - - private: - RefPtr<ExpressionNode> m_base; - Identifier m_ident; - }; - - class DeleteValueNode : public ExpressionNode { - public: - DeleteValueNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL - : ExpressionNode(globalData) - , m_expr(expr) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecUnary; } - - private: - RefPtr<ExpressionNode> m_expr; - }; - - class VoidNode : public ExpressionNode { - public: - VoidNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL - : ExpressionNode(globalData) - , m_expr(expr) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecUnary; } - - private: - RefPtr<ExpressionNode> m_expr; - }; - - class TypeOfResolveNode : public ExpressionNode { - public: - TypeOfResolveNode(JSGlobalData* globalData, const Identifier& ident) JSC_FAST_CALL - : ExpressionNode(globalData, ResultType::string()) - , m_ident(ident) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecUnary; } - - const Identifier& identifier() const JSC_FAST_CALL { return m_ident; } - - protected: - Identifier m_ident; - size_t m_index; // Used by LocalTypeOfNode. - }; - - class TypeOfValueNode : public ExpressionNode { - public: - TypeOfValueNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL - : ExpressionNode(globalData, ResultType::string()) - , m_expr(expr) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecUnary; } - - private: - RefPtr<ExpressionNode> m_expr; - }; - - class PrefixResolveNode : public PrePostResolveNode { - public: - PrefixResolveNode(JSGlobalData* globalData, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL - : PrePostResolveNode(globalData, ident, divot, startOffset, endOffset) - , m_operator(oper) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecUnary; } - - protected: - Operator m_operator; - }; - - class PrefixBracketNode : public ExpressionNode, public ThrowablePrefixedSubExpressionData { - public: - PrefixBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL - : ExpressionNode(globalData) - , ThrowablePrefixedSubExpressionData(divot, startOffset, endOffset) - , m_base(base) - , m_subscript(subscript) - , m_operator(oper) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecUnary; } - - protected: - RefPtr<ExpressionNode> m_base; - RefPtr<ExpressionNode> m_subscript; - Operator m_operator; - }; - - class PrefixDotNode : public ExpressionNode, public ThrowablePrefixedSubExpressionData { - public: - PrefixDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL - : ExpressionNode(globalData) - , ThrowablePrefixedSubExpressionData(divot, startOffset, endOffset) - , m_base(base) - , m_ident(ident) - , m_operator(oper) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecPostfix; } - - protected: - RefPtr<ExpressionNode> m_base; - Identifier m_ident; - Operator m_operator; - }; - - class PrefixErrorNode : public ExpressionNode, public ThrowableExpressionData { - public: - PrefixErrorNode(JSGlobalData* globalData, ExpressionNode* expr, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL - : ExpressionNode(globalData) - , ThrowableExpressionData(divot, startOffset, endOffset) - , m_expr(expr) - , m_operator(oper) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecUnary; } - - private: - RefPtr<ExpressionNode> m_expr; - Operator m_operator; - }; - - class UnaryOpNode : public ExpressionNode { - public: - UnaryOpNode(JSGlobalData* globalData, ExpressionNode* expr) - : ExpressionNode(globalData) - , m_expr(expr) - { - } - - UnaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr) - : ExpressionNode(globalData, type) - , m_expr(expr) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual OpcodeID opcode() const JSC_FAST_CALL = 0; - - protected: - RefPtr<ExpressionNode> m_expr; - }; - - class UnaryPlusNode : public UnaryOpNode { - public: - UnaryPlusNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL - : UnaryOpNode(globalData, ResultType::constNumber(), expr) - { - } - - virtual ExpressionNode* stripUnaryPlus() { return m_expr.get(); } - - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_to_jsnumber; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecUnary; } - }; - - class NegateNode : public UnaryOpNode { - public: - NegateNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL - : UnaryOpNode(globalData, ResultType::reusableNumber(), expr) - { - } - - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_negate; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecUnary; } - }; - - class BitwiseNotNode : public UnaryOpNode { - public: - BitwiseNotNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL - : UnaryOpNode(globalData, ResultType::reusableNumber(), expr) - { - } - - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_bitnot; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecUnary; } - }; - - class LogicalNotNode : public UnaryOpNode { - public: - LogicalNotNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL - : UnaryOpNode(globalData, ResultType::boolean(), expr) - { - } - - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_not; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecUnary; } - }; - - class BinaryOpNode : public ExpressionNode { - public: - BinaryOpNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) - : ExpressionNode(globalData) - , m_expr1(expr1) - , m_expr2(expr2) - , m_rightHasAssignments(rightHasAssignments) - { - } - - BinaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) - : ExpressionNode(globalData, type) - , m_expr1(expr1) - , m_expr2(expr2) - , m_rightHasAssignments(rightHasAssignments) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual OpcodeID opcode() const JSC_FAST_CALL = 0; - - protected: - RefPtr<ExpressionNode> m_expr1; - RefPtr<ExpressionNode> m_expr2; - bool m_rightHasAssignments; - }; - - class ReverseBinaryOpNode : public ExpressionNode { - public: - ReverseBinaryOpNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) - : ExpressionNode(globalData) - , m_expr1(expr1) - , m_expr2(expr2) - , m_rightHasAssignments(rightHasAssignments) - { - } - - ReverseBinaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) - : ExpressionNode(globalData, type) - , m_expr1(expr1) - , m_expr2(expr2) - , m_rightHasAssignments(rightHasAssignments) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual OpcodeID opcode() const JSC_FAST_CALL = 0; - - protected: - RefPtr<ExpressionNode> m_expr1; - RefPtr<ExpressionNode> m_expr2; - bool m_rightHasAssignments; - }; - - class MultNode : public BinaryOpNode { - public: - MultNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL - : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments) - { - } - - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_mul; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecMultiplicative; } - }; - - class DivNode : public BinaryOpNode { - public: - DivNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL - : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments) - { - } - - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_div; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecMultiplicative; } - }; - - class ModNode : public BinaryOpNode { - public: - ModNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL - : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments) - { - } - - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_mod; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecMultiplicative; } - }; - - class AddNode : public BinaryOpNode { - public: - AddNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL - : BinaryOpNode(globalData, ResultType::forAdd(expr1->resultDescriptor(), expr2->resultDescriptor()), expr1, expr2, rightHasAssignments) - { - } - - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_add; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecAdditive; } - }; - - class SubNode : public BinaryOpNode { - public: - SubNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL - : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments) - { - } - - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_sub; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecAdditive; } - }; - - class LeftShiftNode : public BinaryOpNode { - public: - LeftShiftNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL - : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments) - { - } - - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_lshift; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecShift; } - }; - - class RightShiftNode : public BinaryOpNode { - public: - RightShiftNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL - : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments) - { - } - - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_rshift; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecShift; } - }; - - class UnsignedRightShiftNode : public BinaryOpNode { - public: - UnsignedRightShiftNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL - : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments) - { - } - - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_urshift; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecShift; } - }; - - class LessNode : public BinaryOpNode { - public: - LessNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL - : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments) - { - } - - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_less; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecRelational; } - }; - - class GreaterNode : public ReverseBinaryOpNode { - public: - GreaterNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL - : ReverseBinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments) - { - } - - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_less; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecRelational; } - }; - - class LessEqNode : public BinaryOpNode { - public: - LessEqNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL - : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments) - { - } - - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_lesseq; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecRelational; } - }; - - class GreaterEqNode : public ReverseBinaryOpNode { - public: - GreaterEqNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL - : ReverseBinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments) - { - } - - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_lesseq; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecRelational; } - }; - - class ThrowableBinaryOpNode : public BinaryOpNode, public ThrowableExpressionData { - public: - ThrowableBinaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL - : BinaryOpNode(globalData, type, expr1, expr2, rightHasAssignments) - { - } - ThrowableBinaryOpNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL - : BinaryOpNode(globalData, expr1, expr2, rightHasAssignments) - { - } - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - }; - - class InstanceOfNode : public ThrowableBinaryOpNode { - public: - InstanceOfNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL - : ThrowableBinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments) - { - } - - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_instanceof; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecRelational; } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - }; - - class InNode : public ThrowableBinaryOpNode { - public: - InNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL - : ThrowableBinaryOpNode(globalData, expr1, expr2, rightHasAssignments) - { - } - - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_in; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecRelational; } - }; - - class EqualNode : public BinaryOpNode { - public: - EqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL - : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_eq; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecEquality; } - }; - - class NotEqualNode : public BinaryOpNode { - public: - NotEqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL - : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments) - { - } - - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_neq; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecEquality; } - }; - - class StrictEqualNode : public BinaryOpNode { - public: - StrictEqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL - : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_stricteq; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecEquality; } - }; - - class NotStrictEqualNode : public BinaryOpNode { - public: - NotStrictEqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL - : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments) - { - } - - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_nstricteq; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecEquality; } - }; - - class BitAndNode : public BinaryOpNode { - public: - BitAndNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL - : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments) - { - } - - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_bitand; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecBitwiseAnd; } - }; - - class BitOrNode : public BinaryOpNode { - public: - BitOrNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL - : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments) - { - } - - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_bitor; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecBitwiseOr; } - }; - - class BitXOrNode : public BinaryOpNode { - public: - BitXOrNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL - : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments) - { - } - - virtual OpcodeID opcode() const JSC_FAST_CALL { return op_bitxor; } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecBitwiseXor; } - }; - - /** - * m_expr1 && m_expr2, m_expr1 || m_expr2 - */ - class LogicalOpNode : public ExpressionNode { - public: - LogicalOpNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, LogicalOperator oper) JSC_FAST_CALL - : ExpressionNode(globalData, ResultType::boolean()) - , m_expr1(expr1) - , m_expr2(expr2) - , m_operator(oper) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return (m_operator == OpLogicalAnd) ? PrecLogicalAnd : PrecLogicalOr; } - - private: - RefPtr<ExpressionNode> m_expr1; - RefPtr<ExpressionNode> m_expr2; - LogicalOperator m_operator; - }; - - /** - * The ternary operator, "m_logical ? m_expr1 : m_expr2" - */ - class ConditionalNode : public ExpressionNode { - public: - ConditionalNode(JSGlobalData* globalData, ExpressionNode* logical, ExpressionNode* expr1, ExpressionNode* expr2) JSC_FAST_CALL - : ExpressionNode(globalData) - , m_logical(logical) - , m_expr1(expr1) - , m_expr2(expr2) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecConditional; } - - private: - RefPtr<ExpressionNode> m_logical; - RefPtr<ExpressionNode> m_expr1; - RefPtr<ExpressionNode> m_expr2; - }; - - class ReadModifyResolveNode : public ExpressionNode, public ThrowableExpressionData { - public: - ReadModifyResolveNode(JSGlobalData* globalData, const Identifier& ident, Operator oper, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL - : ExpressionNode(globalData) - , ThrowableExpressionData(divot, startOffset, endOffset) - , m_ident(ident) - , m_right(right) - , m_operator(oper) - , m_rightHasAssignments(rightHasAssignments) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecAssignment; } - - protected: - Identifier m_ident; - RefPtr<ExpressionNode> m_right; - size_t m_index; // Used by ReadModifyLocalVarNode. - Operator m_operator : 31; - bool m_rightHasAssignments : 1; - }; - - class AssignResolveNode : public ExpressionNode, public ThrowableExpressionData { - public: - AssignResolveNode(JSGlobalData* globalData, const Identifier& ident, ExpressionNode* right, bool rightHasAssignments) JSC_FAST_CALL - : ExpressionNode(globalData) - , m_ident(ident) - , m_right(right) - , m_rightHasAssignments(rightHasAssignments) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecAssignment; } - - protected: - Identifier m_ident; - RefPtr<ExpressionNode> m_right; - size_t m_index; // Used by ReadModifyLocalVarNode. - bool m_rightHasAssignments; - }; - - class ReadModifyBracketNode : public ExpressionNode, public ThrowableSubExpressionData { - public: - ReadModifyBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, Operator oper, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL - : ExpressionNode(globalData) - , ThrowableSubExpressionData(divot, startOffset, endOffset) - , m_base(base) - , m_subscript(subscript) - , m_right(right) - , m_operator(oper) - , m_subscriptHasAssignments(subscriptHasAssignments) - , m_rightHasAssignments(rightHasAssignments) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecAssignment; } - - protected: - RefPtr<ExpressionNode> m_base; - RefPtr<ExpressionNode> m_subscript; - RefPtr<ExpressionNode> m_right; - Operator m_operator : 30; - bool m_subscriptHasAssignments : 1; - bool m_rightHasAssignments : 1; - }; - - class AssignBracketNode : public ExpressionNode, public ThrowableExpressionData { - public: - AssignBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL - : ExpressionNode(globalData) - , ThrowableExpressionData(divot, startOffset, endOffset) - , m_base(base) - , m_subscript(subscript) - , m_right(right) - , m_subscriptHasAssignments(subscriptHasAssignments) - , m_rightHasAssignments(rightHasAssignments) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecAssignment; } - - protected: - RefPtr<ExpressionNode> m_base; - RefPtr<ExpressionNode> m_subscript; - RefPtr<ExpressionNode> m_right; - bool m_subscriptHasAssignments : 1; - bool m_rightHasAssignments : 1; - }; - - class AssignDotNode : public ExpressionNode, public ThrowableExpressionData { - public: - AssignDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL - : ExpressionNode(globalData) - , ThrowableExpressionData(divot, startOffset, endOffset) - , m_base(base) - , m_ident(ident) - , m_right(right) - , m_rightHasAssignments(rightHasAssignments) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecAssignment; } - - protected: - RefPtr<ExpressionNode> m_base; - Identifier m_ident; - RefPtr<ExpressionNode> m_right; - bool m_rightHasAssignments; - }; - - class ReadModifyDotNode : public ExpressionNode, public ThrowableSubExpressionData { - public: - ReadModifyDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, Operator oper, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL - : ExpressionNode(globalData) - , ThrowableSubExpressionData(divot, startOffset, endOffset) - , m_base(base) - , m_ident(ident) - , m_right(right) - , m_operator(oper) - , m_rightHasAssignments(rightHasAssignments) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecAssignment; } - - protected: - RefPtr<ExpressionNode> m_base; - Identifier m_ident; - RefPtr<ExpressionNode> m_right; - Operator m_operator : 31; - bool m_rightHasAssignments : 1; - }; - - class AssignErrorNode : public ExpressionNode, public ThrowableExpressionData { - public: - AssignErrorNode(JSGlobalData* globalData, ExpressionNode* left, Operator oper, ExpressionNode* right, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL - : ExpressionNode(globalData) - , ThrowableExpressionData(divot, startOffset, endOffset) - , m_left(left) - , m_operator(oper) - , m_right(right) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecAssignment; } - - protected: - RefPtr<ExpressionNode> m_left; - Operator m_operator; - RefPtr<ExpressionNode> m_right; - }; - - class CommaNode : public ExpressionNode { - public: - CommaNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2) JSC_FAST_CALL - : ExpressionNode(globalData) - , m_expr1(expr1) - , m_expr2(expr2) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecExpression; } - - private: - RefPtr<ExpressionNode> m_expr1; - RefPtr<ExpressionNode> m_expr2; - }; - - class VarDeclCommaNode : public CommaNode { - public: - VarDeclCommaNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2) JSC_FAST_CALL - : CommaNode(globalData, expr1, expr2) - { - } - virtual Precedence precedence() const { return PrecAssignment; } - }; - - class ConstDeclNode : public ExpressionNode { - public: - ConstDeclNode(JSGlobalData* globalData, const Identifier& ident, ExpressionNode* in) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; } - PassRefPtr<ConstDeclNode> releaseNext() JSC_FAST_CALL { return m_next.release(); } - - Identifier m_ident; - ListRefPtr<ConstDeclNode> m_next; - RefPtr<ExpressionNode> m_init; - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual RegisterID* emitCodeSingle(CodeGenerator&) JSC_FAST_CALL; - }; - - class ConstStatementNode : public StatementNode { - public: - ConstStatementNode(JSGlobalData* globalData, ConstDeclNode* next) JSC_FAST_CALL - : StatementNode(globalData) - , m_next(next) - { - } - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - private: - RefPtr<ConstDeclNode> m_next; - }; - - typedef Vector<RefPtr<StatementNode> > StatementVector; - - class SourceElements : public ParserRefCounted { - public: - SourceElements(JSGlobalData* globalData) : ParserRefCounted(globalData) {} - - void append(PassRefPtr<StatementNode>); - void releaseContentsIntoVector(StatementVector& destination) - { - ASSERT(destination.isEmpty()); - m_statements.swap(destination); - } - - private: - StatementVector m_statements; - }; - - class BlockNode : public StatementNode { - public: - BlockNode(JSGlobalData*, SourceElements* children) JSC_FAST_CALL; - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - - StatementVector& children() { return m_children; } - - virtual bool isBlock() const JSC_FAST_CALL { return true; } - protected: - StatementVector m_children; - }; - - class EmptyStatementNode : public StatementNode { - public: - EmptyStatementNode(JSGlobalData* globalData) JSC_FAST_CALL // debug - : StatementNode(globalData) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual bool isEmptyStatement() const JSC_FAST_CALL { return true; } - }; - - class DebuggerStatementNode : public StatementNode { - public: - DebuggerStatementNode(JSGlobalData* globalData) JSC_FAST_CALL - : StatementNode(globalData) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - }; - - class ExprStatementNode : public StatementNode { - public: - ExprStatementNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL - : StatementNode(globalData) - , m_expr(expr) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - - private: - RefPtr<ExpressionNode> m_expr; - }; - - class VarStatementNode : public StatementNode { - public: - VarStatementNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL - : StatementNode(globalData) - , m_expr(expr) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - - private: - RefPtr<ExpressionNode> m_expr; - }; - - class IfNode : public StatementNode { - public: - IfNode(JSGlobalData* globalData, ExpressionNode* condition, StatementNode* ifBlock) JSC_FAST_CALL - : StatementNode(globalData) - , m_condition(condition) - , m_ifBlock(ifBlock) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - - protected: - RefPtr<ExpressionNode> m_condition; - RefPtr<StatementNode> m_ifBlock; - }; - - class IfElseNode : public IfNode { - public: - IfElseNode(JSGlobalData* globalData, ExpressionNode* condition, StatementNode* ifBlock, StatementNode* elseBlock) JSC_FAST_CALL - : IfNode(globalData, condition, ifBlock) - , m_elseBlock(elseBlock) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - - private: - RefPtr<StatementNode> m_elseBlock; - }; - - class DoWhileNode : public StatementNode { - public: - DoWhileNode(JSGlobalData* globalData, StatementNode* statement, ExpressionNode* expr) JSC_FAST_CALL - : StatementNode(globalData) - , m_statement(statement) - , m_expr(expr) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - - virtual bool isLoop() const JSC_FAST_CALL { return true; } - private: - RefPtr<StatementNode> m_statement; - RefPtr<ExpressionNode> m_expr; - }; - - class WhileNode : public StatementNode { - public: - WhileNode(JSGlobalData* globalData, ExpressionNode* expr, StatementNode* statement) JSC_FAST_CALL - : StatementNode(globalData) - , m_expr(expr) - , m_statement(statement) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - - virtual bool isLoop() const JSC_FAST_CALL { return true; } - private: - RefPtr<ExpressionNode> m_expr; - RefPtr<StatementNode> m_statement; - }; - - class ForNode : public StatementNode { - public: - ForNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, ExpressionNode* expr3, StatementNode* statement, bool expr1WasVarDecl) JSC_FAST_CALL - : StatementNode(globalData) - , m_expr1(expr1) - , m_expr2(expr2) - , m_expr3(expr3) - , m_statement(statement) - , m_expr1WasVarDecl(expr1 && expr1WasVarDecl) - { - ASSERT(statement); - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - - virtual bool isLoop() const JSC_FAST_CALL { return true; } - private: - RefPtr<ExpressionNode> m_expr1; - RefPtr<ExpressionNode> m_expr2; - RefPtr<ExpressionNode> m_expr3; - RefPtr<StatementNode> m_statement; - bool m_expr1WasVarDecl; - }; - - class ForInNode : public StatementNode, public ThrowableExpressionData { - public: - ForInNode(JSGlobalData*, ExpressionNode*, ExpressionNode*, StatementNode*) JSC_FAST_CALL; - ForInNode(JSGlobalData*, const Identifier&, ExpressionNode*, ExpressionNode*, StatementNode*, int divot, int startOffset, int endOffset) JSC_FAST_CALL; - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - - virtual bool isLoop() const JSC_FAST_CALL { return true; } - private: - Identifier m_ident; - RefPtr<ExpressionNode> m_init; - RefPtr<ExpressionNode> m_lexpr; - RefPtr<ExpressionNode> m_expr; - RefPtr<StatementNode> m_statement; - bool m_identIsVarDecl; - }; - - class ContinueNode : public StatementNode, public ThrowableExpressionData { - public: - ContinueNode(JSGlobalData* globalData) JSC_FAST_CALL - : StatementNode(globalData) - { - } - - ContinueNode(JSGlobalData* globalData, const Identifier& ident) JSC_FAST_CALL - : StatementNode(globalData) - , m_ident(ident) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - - private: - Identifier m_ident; - }; - - class BreakNode : public StatementNode, public ThrowableExpressionData { - public: - BreakNode(JSGlobalData* globalData) JSC_FAST_CALL - : StatementNode(globalData) - { - } - - BreakNode(JSGlobalData* globalData, const Identifier& ident) JSC_FAST_CALL - : StatementNode(globalData) - , m_ident(ident) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - - private: - Identifier m_ident; - }; - - class ReturnNode : public StatementNode, public ThrowableExpressionData { - public: - ReturnNode(JSGlobalData* globalData, ExpressionNode* value) JSC_FAST_CALL - : StatementNode(globalData) - , m_value(value) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual bool isReturnNode() const JSC_FAST_CALL { return true; } - - private: - RefPtr<ExpressionNode> m_value; - }; - - class WithNode : public StatementNode { - public: - WithNode(JSGlobalData* globalData, ExpressionNode* expr, StatementNode* statement, uint32_t divot, uint32_t expressionLength) JSC_FAST_CALL - : StatementNode(globalData) - , m_expr(expr) - , m_statement(statement) - , m_divot(divot) - , m_expressionLength(expressionLength) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - - private: - RefPtr<ExpressionNode> m_expr; - RefPtr<StatementNode> m_statement; - uint32_t m_divot; - uint32_t m_expressionLength; - }; - - class LabelNode : public StatementNode, public ThrowableExpressionData { - public: - LabelNode(JSGlobalData* globalData, const Identifier& name, StatementNode* statement) JSC_FAST_CALL - : StatementNode(globalData) - , m_name(name) - , m_statement(statement) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - - private: - Identifier m_name; - RefPtr<StatementNode> m_statement; - }; - - class ThrowNode : public StatementNode, public ThrowableExpressionData { - public: - ThrowNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL - : StatementNode(globalData) - , m_expr(expr) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - - private: - RefPtr<ExpressionNode> m_expr; - }; - - class TryNode : public StatementNode { - public: - TryNode(JSGlobalData* globalData, StatementNode* tryBlock, const Identifier& exceptionIdent, StatementNode* catchBlock, StatementNode* finallyBlock) JSC_FAST_CALL - : StatementNode(globalData) - , m_tryBlock(tryBlock) - , m_exceptionIdent(exceptionIdent) - , m_catchBlock(catchBlock) - , m_finallyBlock(finallyBlock) - { - } - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* dst = 0) JSC_FAST_CALL; - - private: - RefPtr<StatementNode> m_tryBlock; - Identifier m_exceptionIdent; - RefPtr<StatementNode> m_catchBlock; - RefPtr<StatementNode> m_finallyBlock; - }; - - class ParameterNode : public Node { - public: - ParameterNode(JSGlobalData* globalData, const Identifier& ident) JSC_FAST_CALL - : Node(globalData) - , m_ident(ident) - { - } - - ParameterNode(JSGlobalData* globalData, ParameterNode* l, const Identifier& ident) JSC_FAST_CALL - : Node(globalData) - , m_ident(ident) - { - l->m_next = this; - } - - Identifier ident() JSC_FAST_CALL { return m_ident; } - ParameterNode *nextParam() JSC_FAST_CALL { return m_next.get(); } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - PassRefPtr<ParameterNode> releaseNext() JSC_FAST_CALL { return m_next.release(); } - virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; } - - private: - friend class FuncDeclNode; - friend class FuncExprNode; - Identifier m_ident; - ListRefPtr<ParameterNode> m_next; - }; - - class ScopeNode : public BlockNode { - public: - ScopeNode(JSGlobalData*, const SourceCode&, SourceElements*, VarStack*, FunctionStack*, CodeFeatures, int numConstants) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - - const SourceCode& source() const { return m_source; } - const UString& sourceURL() const JSC_FAST_CALL { return m_source.provider()->url(); } - intptr_t sourceID() const { return m_source.provider()->asID(); } - - bool usesEval() const { return m_features & EvalFeature; } - bool usesArguments() const { return m_features & ArgumentsFeature; } - void setUsesArguments() { m_features |= ArgumentsFeature; } - bool usesThis() const { return m_features & ThisFeature; } - bool needsActivation() const { return m_features & (EvalFeature | ClosureFeature | WithFeature | CatchFeature); } - - VarStack& varStack() { return m_varStack; } - FunctionStack& functionStack() { return m_functionStack; } - - int neededConstants() - { - // We may need 1 more constant than the count given by the parser, - // because of the various uses of jsUndefined(). - return m_numConstants + 1; - } - - protected: - void setSource(const SourceCode& source) { m_source = source; } - - VarStack m_varStack; - FunctionStack m_functionStack; - - private: - SourceCode m_source; - CodeFeatures m_features; - int m_numConstants; - }; - - class ProgramNode : public ScopeNode { - public: - static ProgramNode* create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants) JSC_FAST_CALL; - - ProgramCodeBlock& byteCode(ScopeChainNode* scopeChain) JSC_FAST_CALL - { - if (!m_code) - generateCode(scopeChain); - return *m_code; - } - - private: - ProgramNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants) JSC_FAST_CALL; - - void generateCode(ScopeChainNode*) JSC_FAST_CALL; - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - Vector<size_t> m_varIndexes; // Storage indexes belonging to the nodes in m_varStack. (Recorded to avoid double lookup.) - Vector<size_t> m_functionIndexes; // Storage indexes belonging to the nodes in m_functionStack. (Recorded to avoid double lookup.) - - OwnPtr<ProgramCodeBlock> m_code; - }; - - class EvalNode : public ScopeNode { - public: - static EvalNode* create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants) JSC_FAST_CALL; - - EvalCodeBlock& byteCode(ScopeChainNode* scopeChain) JSC_FAST_CALL - { - if (!m_code) - generateCode(scopeChain); - return *m_code; - } - - private: - EvalNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants) JSC_FAST_CALL; - - void generateCode(ScopeChainNode*) JSC_FAST_CALL; - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - OwnPtr<EvalCodeBlock> m_code; - }; - - class FunctionBodyNode : public ScopeNode { - public: - static FunctionBodyNode* create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants) JSC_FAST_CALL; - static FunctionBodyNode* create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, CodeFeatures, int numConstants) JSC_FAST_CALL; - ~FunctionBodyNode(); - - const Identifier* parameters() const JSC_FAST_CALL { return m_parameters; } - size_t parameterCount() const { return m_parameterCount; } - UString paramString() const JSC_FAST_CALL; - Identifier* copyParameters(); - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - SymbolTable& symbolTable() { return m_symbolTable; } // FIXME: Remove this - - CodeBlock& byteCode(ScopeChainNode* scopeChain) JSC_FAST_CALL - { - ASSERT(scopeChain); - if (!m_code) - generateCode(scopeChain); - return *m_code; - } - - CodeBlock& generatedByteCode() JSC_FAST_CALL - { - ASSERT(m_code); - return *m_code; - } - - bool isGenerated() JSC_FAST_CALL - { - return m_code; - } - - void mark(); - - void finishParsing(const SourceCode&, ParameterNode*); - void finishParsing(Identifier* parameters, size_t parameterCount); - - UString toSourceString() const JSC_FAST_CALL { return UString("{") + source().toString() + UString("}"); } - - // These objects are ref/deref'd a lot in the scope chain, so this is a faster ref/deref. - // If the virtual machine changes so this doesn't happen as much we can change back. - void ref() - { - if (++m_refCount == 1) - ScopeNode::ref(); - } - void deref() - { - ASSERT(m_refCount); - if (!--m_refCount) - ScopeNode::deref(); - } - - protected: - FunctionBodyNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants) JSC_FAST_CALL; - - private: - void generateCode(ScopeChainNode*) JSC_FAST_CALL; - - Identifier* m_parameters; - size_t m_parameterCount; - SymbolTable m_symbolTable; - OwnPtr<CodeBlock> m_code; - unsigned m_refCount; - }; - - class FuncExprNode : public ExpressionNode { - public: - FuncExprNode(JSGlobalData* globalData, const Identifier& ident, FunctionBodyNode* body, const SourceCode& source, ParameterNode* parameter = 0) JSC_FAST_CALL - : ExpressionNode(globalData) - , m_ident(ident) - , m_parameter(parameter) - , m_body(body) - { - m_body->finishParsing(source, m_parameter.get()); - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - JSFunction* makeFunction(ExecState*, ScopeChainNode*) JSC_FAST_CALL; - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { return PrecMember; } - virtual bool needsParensIfLeftmost() const { return true; } - - FunctionBodyNode* body() { return m_body.get(); } - - private: - // Used for streamTo - friend class PropertyNode; - Identifier m_ident; - RefPtr<ParameterNode> m_parameter; - RefPtr<FunctionBodyNode> m_body; - }; - - class FuncDeclNode : public StatementNode { - public: - FuncDeclNode(JSGlobalData* globalData, const Identifier& ident, FunctionBodyNode* body, const SourceCode& source, ParameterNode* parameter = 0) JSC_FAST_CALL - : StatementNode(globalData) - , m_ident(ident) - , m_parameter(parameter) - , m_body(body) - { - m_body->finishParsing(source, m_parameter.get()); - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - JSFunction* makeFunction(ExecState*, ScopeChainNode*) JSC_FAST_CALL; - - Identifier m_ident; - - FunctionBodyNode* body() { return m_body.get(); } - - private: - RefPtr<ParameterNode> m_parameter; - RefPtr<FunctionBodyNode> m_body; - }; - - class CaseClauseNode : public Node { - public: - CaseClauseNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL - : Node(globalData) - , m_expr(expr) - { - } - - CaseClauseNode(JSGlobalData* globalData, ExpressionNode* expr, SourceElements* children) JSC_FAST_CALL - : Node(globalData) - , m_expr(expr) - { - if (children) - children->releaseContentsIntoVector(m_children); - } - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; } - - ExpressionNode* expr() const { return m_expr.get(); } - StatementVector& children() { return m_children; } - - private: - RefPtr<ExpressionNode> m_expr; - StatementVector m_children; - }; - - class ClauseListNode : public Node { - public: - ClauseListNode(JSGlobalData* globalData, CaseClauseNode* clause) JSC_FAST_CALL - : Node(globalData) - , m_clause(clause) - { - } - - ClauseListNode(JSGlobalData* globalData, ClauseListNode* clauseList, CaseClauseNode* clause) JSC_FAST_CALL - : Node(globalData) - , m_clause(clause) - { - clauseList->m_next = this; - } - - CaseClauseNode* getClause() const JSC_FAST_CALL { return m_clause.get(); } - ClauseListNode* getNext() const JSC_FAST_CALL { return m_next.get(); } - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - PassRefPtr<ClauseListNode> releaseNext() JSC_FAST_CALL { return m_next.release(); } - virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; } - - private: - friend class CaseBlockNode; - RefPtr<CaseClauseNode> m_clause; - ListRefPtr<ClauseListNode> m_next; - }; - - class CaseBlockNode : public Node { - public: - CaseBlockNode(JSGlobalData* globalData, ClauseListNode* list1, CaseClauseNode* defaultClause, ClauseListNode* list2) JSC_FAST_CALL - : Node(globalData) - , m_list1(list1) - , m_defaultClause(defaultClause) - , m_list2(list2) - { - } - - RegisterID* emitCodeForBlock(CodeGenerator&, RegisterID* input, RegisterID* dst = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; } - - private: - SwitchInfo::SwitchType tryOptimizedSwitch(Vector<ExpressionNode*, 8>& literalVector, int32_t& min_num, int32_t& max_num); - RefPtr<ClauseListNode> m_list1; - RefPtr<CaseClauseNode> m_defaultClause; - RefPtr<ClauseListNode> m_list2; - }; - - class SwitchNode : public StatementNode { - public: - SwitchNode(JSGlobalData* globalData, ExpressionNode* expr, CaseBlockNode* block) JSC_FAST_CALL - : StatementNode(globalData) - , m_expr(expr) - , m_block(block) - { - } - - virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; - - virtual void streamTo(SourceStream&) const JSC_FAST_CALL; - - private: - RefPtr<ExpressionNode> m_expr; - RefPtr<CaseBlockNode> m_block; - }; - - struct ElementList { - ElementNode* head; - ElementNode* tail; - }; - - struct PropertyList { - PropertyListNode* head; - PropertyListNode* tail; - }; - - struct ArgumentList { - ArgumentListNode* head; - ArgumentListNode* tail; - }; - - struct ConstDeclList { - ConstDeclNode* head; - ConstDeclNode* tail; - }; - - struct ParameterList { - ParameterNode* head; - ParameterNode* tail; - }; - - struct ClauseList { - ClauseListNode* head; - ClauseListNode* tail; - }; - -} // namespace JSC - -#endif // NODES_H_ diff --git a/JavaScriptCore/kjs/nodes2string.cpp b/JavaScriptCore/kjs/nodes2string.cpp deleted file mode 100644 index 4afefe0..0000000 --- a/JavaScriptCore/kjs/nodes2string.cpp +++ /dev/null @@ -1,936 +0,0 @@ -/* - * Copyright (C) 2002 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2007 Eric Seidel <eric@webkit.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "nodes.h" - -#include <wtf/MathExtras.h> -#include <wtf/StringExtras.h> -#include <wtf/unicode/Unicode.h> - -using namespace WTF; -using namespace Unicode; - -namespace JSC { - -// A simple text streaming class that helps with code indentation. - -enum EndlType { Endl }; -enum IndentType { Indent }; -enum UnindentType { Unindent }; -enum DotExprType { DotExpr }; - -class SourceStream { -public: - SourceStream() - : m_numberNeedsParens(false) - , m_atStartOfStatement(true) - , m_precedence(PrecExpression) - { - } - - UString toString() const { return m_string; } - - SourceStream& operator<<(const Identifier&); - SourceStream& operator<<(const UString&); - SourceStream& operator<<(const char*); - SourceStream& operator<<(double); - SourceStream& operator<<(char); - SourceStream& operator<<(EndlType); - SourceStream& operator<<(IndentType); - SourceStream& operator<<(UnindentType); - SourceStream& operator<<(DotExprType); - SourceStream& operator<<(Precedence); - SourceStream& operator<<(const Node*); - template <typename T> SourceStream& operator<<(const RefPtr<T>& n) { return *this << n.get(); } - -private: - UString m_string; - UString m_spacesForIndentation; - bool m_numberNeedsParens; - bool m_atStartOfStatement; - Precedence m_precedence; -}; - -// -------- - -static UString escapeStringForPrettyPrinting(const UString& s) -{ - UString escapedString; - - for (int i = 0; i < s.size(); i++) { - UChar c = s.data()[i]; - switch (c) { - case '\"': - escapedString += "\\\""; - break; - case '\n': - escapedString += "\\n"; - break; - case '\r': - escapedString += "\\r"; - break; - case '\t': - escapedString += "\\t"; - break; - case '\\': - escapedString += "\\\\"; - break; - default: - if (c < 128 && isPrintableChar(c)) - escapedString.append(c); - else { - char hexValue[7]; - snprintf(hexValue, 7, "\\u%04x", c); - escapedString += hexValue; - } - } - } - - return escapedString; -} - -static const char* operatorString(Operator oper) -{ - switch (oper) { - case OpEqual: - return "="; - case OpMultEq: - return "*="; - case OpDivEq: - return "/="; - case OpPlusEq: - return "+="; - case OpMinusEq: - return "-="; - case OpLShift: - return "<<="; - case OpRShift: - return ">>="; - case OpURShift: - return ">>>="; - case OpAndEq: - return "&="; - case OpXOrEq: - return "^="; - case OpOrEq: - return "|="; - case OpModEq: - return "%="; - case OpPlusPlus: - return "++"; - case OpMinusMinus: - return "--"; - } - ASSERT_NOT_REACHED(); - return "???"; -} - -static bool isParserRoundTripNumber(const UString& string) -{ - double number = string.toDouble(false, false); - if (isnan(number) || isinf(number)) - return false; - return string == UString::from(number); -} - -// -------- - -SourceStream& SourceStream::operator<<(char c) -{ - m_numberNeedsParens = false; - m_atStartOfStatement = false; - // use unsigned char to zero-extend instead of sign-extend - UChar ch(static_cast<unsigned char>(c)); - m_string.append(ch); - return *this; -} - -SourceStream& SourceStream::operator<<(const char* s) -{ - m_numberNeedsParens = false; - m_atStartOfStatement = false; - m_string += s; - return *this; -} - -SourceStream& SourceStream::operator<<(double value) -{ - bool needParens = m_numberNeedsParens; - m_numberNeedsParens = false; - m_atStartOfStatement = false; - - if (needParens) - m_string.append('('); - m_string += UString::from(value); - if (needParens) - m_string.append(')'); - - return *this; -} - -SourceStream& SourceStream::operator<<(const UString& s) -{ - m_numberNeedsParens = false; - m_atStartOfStatement = false; - m_string += s; - return *this; -} - -SourceStream& SourceStream::operator<<(const Identifier& s) -{ - m_numberNeedsParens = false; - m_atStartOfStatement = false; - m_string += s.ustring(); - return *this; -} - -SourceStream& SourceStream::operator<<(const Node* n) -{ - bool needParens = (m_precedence != PrecExpression && n->precedence() > m_precedence) || (m_atStartOfStatement && n->needsParensIfLeftmost()); - m_precedence = PrecExpression; - if (!n) - return *this; - if (needParens) { - m_numberNeedsParens = false; - m_string.append('('); - } - n->streamTo(*this); - if (needParens) - m_string.append(')'); - return *this; -} - -SourceStream& SourceStream::operator<<(EndlType) -{ - m_numberNeedsParens = false; - m_atStartOfStatement = true; - m_string.append('\n'); - m_string.append(m_spacesForIndentation); - return *this; -} - -SourceStream& SourceStream::operator<<(IndentType) -{ - m_numberNeedsParens = false; - m_atStartOfStatement = false; - m_spacesForIndentation += " "; - return *this; -} - -SourceStream& SourceStream::operator<<(UnindentType) -{ - m_numberNeedsParens = false; - m_atStartOfStatement = false; - m_spacesForIndentation = m_spacesForIndentation.substr(0, m_spacesForIndentation.size() - 2); - return *this; -} - -inline SourceStream& SourceStream::operator<<(DotExprType) -{ - m_numberNeedsParens = true; - return *this; -} - -inline SourceStream& SourceStream::operator<<(Precedence precedence) -{ - m_precedence = precedence; - return *this; -} - -static void streamLeftAssociativeBinaryOperator(SourceStream& s, Precedence precedence, - const char* operatorString, const Node* left, const Node* right) -{ - s << precedence << left - << ' ' << operatorString << ' ' - << static_cast<Precedence>(precedence - 1) << right; -} - -template <typename T> static inline void streamLeftAssociativeBinaryOperator(SourceStream& s, - Precedence p, const char* o, const RefPtr<T>& l, const RefPtr<T>& r) -{ - streamLeftAssociativeBinaryOperator(s, p, o, l.get(), r.get()); -} - -static inline void bracketNodeStreamTo(SourceStream& s, const RefPtr<ExpressionNode>& base, const RefPtr<ExpressionNode>& subscript) -{ - s << PrecCall << base.get() << "[" << subscript.get() << "]"; -} - -static inline void dotNodeStreamTo(SourceStream& s, const RefPtr<ExpressionNode>& base, const Identifier& ident) -{ - s << DotExpr << PrecCall << base.get() << "." << ident; -} - -// -------- - -UString Node::toString() const -{ - SourceStream stream; - streamTo(stream); - return stream.toString(); -} - -// -------- - -void NullNode::streamTo(SourceStream& s) const -{ - s << "null"; -} - -void BooleanNode::streamTo(SourceStream& s) const -{ - s << (m_value ? "true" : "false"); -} - -void NumberNode::streamTo(SourceStream& s) const -{ - s << value(); -} - -void StringNode::streamTo(SourceStream& s) const -{ - s << '"' << escapeStringForPrettyPrinting(m_value.ustring()) << '"'; -} - -void RegExpNode::streamTo(SourceStream& s) const -{ - s << '/' << m_pattern << '/' << m_flags; -} - -void ThisNode::streamTo(SourceStream& s) const -{ - s << "this"; -} - -void ResolveNode::streamTo(SourceStream& s) const -{ - s << m_ident; -} - -void ElementNode::streamTo(SourceStream& s) const -{ - for (const ElementNode* n = this; n; n = n->m_next.get()) { - for (int i = 0; i < n->m_elision; i++) - s << ','; - s << PrecAssignment << n->m_node; - if (n->m_next) - s << ','; - } -} - -void ArrayNode::streamTo(SourceStream& s) const -{ - s << '[' << m_element; - for (int i = 0; i < m_elision; i++) - s << ','; - // Parser consumes one elision comma if there's array elements - // present in the expression. - if (m_optional && m_element) - s << ','; - s << ']'; -} - -void ObjectLiteralNode::streamTo(SourceStream& s) const -{ - if (m_list) - s << "{ " << m_list << " }"; - else - s << "{ }"; -} - -void PropertyListNode::streamTo(SourceStream& s) const -{ - s << m_node; - for (const PropertyListNode* n = m_next.get(); n; n = n->m_next.get()) - s << ", " << n->m_node; -} - -void PropertyNode::streamTo(SourceStream& s) const -{ - switch (m_type) { - case Constant: { - UString propertyName = name().ustring(); - if (isParserRoundTripNumber(propertyName)) - s << propertyName; - else - s << '"' << escapeStringForPrettyPrinting(propertyName) << '"'; - s << ": " << PrecAssignment << m_assign; - break; - } - case Getter: - case Setter: { - const FuncExprNode* func = static_cast<const FuncExprNode*>(m_assign.get()); - if (m_type == Getter) - s << "get "; - else - s << "set "; - s << escapeStringForPrettyPrinting(name().ustring()) - << "(" << func->m_parameter << ')' << func->m_body; - break; - } - } -} - -void BracketAccessorNode::streamTo(SourceStream& s) const -{ - bracketNodeStreamTo(s, m_base, m_subscript); -} - -void DotAccessorNode::streamTo(SourceStream& s) const -{ - dotNodeStreamTo(s, m_base, m_ident); -} - -void ArgumentListNode::streamTo(SourceStream& s) const -{ - s << PrecAssignment << m_expr; - for (ArgumentListNode* n = m_next.get(); n; n = n->m_next.get()) - s << ", " << PrecAssignment << n->m_expr; -} - -void ArgumentsNode::streamTo(SourceStream& s) const -{ - s << '(' << m_listNode << ')'; -} - -void NewExprNode::streamTo(SourceStream& s) const -{ - s << "new " << PrecMember << m_expr << m_args; -} - -void EvalFunctionCallNode::streamTo(SourceStream& s) const -{ - s << "eval" << m_args; -} - -void FunctionCallValueNode::streamTo(SourceStream& s) const -{ - s << PrecCall << m_expr << m_args; -} - -void FunctionCallResolveNode::streamTo(SourceStream& s) const -{ - s << m_ident << m_args; -} - -void FunctionCallBracketNode::streamTo(SourceStream& s) const -{ - bracketNodeStreamTo(s, m_base, m_subscript); - s << m_args; -} - -void FunctionCallDotNode::streamTo(SourceStream& s) const -{ - dotNodeStreamTo(s, m_base, m_ident); - s << m_args; -} - -void PostfixResolveNode::streamTo(SourceStream& s) const -{ - s << m_ident << operatorString(m_operator); -} - -void PostfixBracketNode::streamTo(SourceStream& s) const -{ - bracketNodeStreamTo(s, m_base, m_subscript); - s << operatorString(m_operator); -} - -void PostfixDotNode::streamTo(SourceStream& s) const -{ - dotNodeStreamTo(s, m_base, m_ident); - s << operatorString(m_operator); -} - -void PostfixErrorNode::streamTo(SourceStream& s) const -{ - s << PrecLeftHandSide << m_expr; - if (m_operator == OpPlusPlus) - s << "++"; - else - s << "--"; -} - -void DeleteResolveNode::streamTo(SourceStream& s) const -{ - s << "delete " << m_ident; -} - -void DeleteBracketNode::streamTo(SourceStream& s) const -{ - s << "delete "; - bracketNodeStreamTo(s, m_base, m_subscript); -} - -void DeleteDotNode::streamTo(SourceStream& s) const -{ - s << "delete "; - dotNodeStreamTo(s, m_base, m_ident); -} - -void DeleteValueNode::streamTo(SourceStream& s) const -{ - s << "delete " << PrecUnary << m_expr; -} - -void VoidNode::streamTo(SourceStream& s) const -{ - s << "void " << PrecUnary << m_expr; -} - -void TypeOfValueNode::streamTo(SourceStream& s) const -{ - s << "typeof " << PrecUnary << m_expr; -} - -void TypeOfResolveNode::streamTo(SourceStream& s) const -{ - s << "typeof " << m_ident; -} - -void PrefixResolveNode::streamTo(SourceStream& s) const -{ - s << operatorString(m_operator) << m_ident; -} - -void PrefixBracketNode::streamTo(SourceStream& s) const -{ - s << operatorString(m_operator); - bracketNodeStreamTo(s, m_base, m_subscript); -} - -void PrefixDotNode::streamTo(SourceStream& s) const -{ - s << operatorString(m_operator); - dotNodeStreamTo(s, m_base, m_ident); -} - -void PrefixErrorNode::streamTo(SourceStream& s) const -{ - if (m_operator == OpPlusPlus) - s << "++" << PrecUnary << m_expr; - else - s << "--" << PrecUnary << m_expr; -} - -void UnaryPlusNode::streamTo(SourceStream& s) const -{ - s << "+ " << PrecUnary << m_expr; -} - -void NegateNode::streamTo(SourceStream& s) const -{ - s << "- " << PrecUnary << m_expr; -} - -void BitwiseNotNode::streamTo(SourceStream& s) const -{ - s << "~" << PrecUnary << m_expr; -} - -void LogicalNotNode::streamTo(SourceStream& s) const -{ - s << "!" << PrecUnary << m_expr; -} - -void MultNode::streamTo(SourceStream& s) const -{ - streamLeftAssociativeBinaryOperator(s, precedence(), "*", m_expr1, m_expr2); -} - -void DivNode::streamTo(SourceStream& s) const -{ - streamLeftAssociativeBinaryOperator(s, precedence(), "/", m_expr1, m_expr2); -} - -void ModNode::streamTo(SourceStream& s) const -{ - streamLeftAssociativeBinaryOperator(s, precedence(), "%", m_expr1, m_expr2); -} - -void AddNode::streamTo(SourceStream& s) const -{ - streamLeftAssociativeBinaryOperator(s, precedence(), "+", m_expr1, m_expr2); -} - -void SubNode::streamTo(SourceStream& s) const -{ - streamLeftAssociativeBinaryOperator(s, precedence(), "-", m_expr1, m_expr2); -} - -void LeftShiftNode::streamTo(SourceStream& s) const -{ - streamLeftAssociativeBinaryOperator(s, precedence(), "<<", m_expr1, m_expr2); -} - -void RightShiftNode::streamTo(SourceStream& s) const -{ - streamLeftAssociativeBinaryOperator(s, precedence(), ">>", m_expr1, m_expr2); -} - -void UnsignedRightShiftNode::streamTo(SourceStream& s) const -{ - streamLeftAssociativeBinaryOperator(s, precedence(), ">>>", m_expr1, m_expr2); -} - -void LessNode::streamTo(SourceStream& s) const -{ - streamLeftAssociativeBinaryOperator(s, precedence(), "<", m_expr1, m_expr2); -} - -void GreaterNode::streamTo(SourceStream& s) const -{ - streamLeftAssociativeBinaryOperator(s, precedence(), ">", m_expr1, m_expr2); -} - -void LessEqNode::streamTo(SourceStream& s) const -{ - streamLeftAssociativeBinaryOperator(s, precedence(), "<=", m_expr1, m_expr2); -} - -void GreaterEqNode::streamTo(SourceStream& s) const -{ - streamLeftAssociativeBinaryOperator(s, precedence(), ">=", m_expr1, m_expr2); -} - -void InstanceOfNode::streamTo(SourceStream& s) const -{ - streamLeftAssociativeBinaryOperator(s, precedence(), "instanceof", m_expr1, m_expr2); -} - -void InNode::streamTo(SourceStream& s) const -{ - streamLeftAssociativeBinaryOperator(s, precedence(), "in", m_expr1, m_expr2); -} - -void EqualNode::streamTo(SourceStream& s) const -{ - streamLeftAssociativeBinaryOperator(s, precedence(), "==", m_expr1, m_expr2); -} - -void NotEqualNode::streamTo(SourceStream& s) const -{ - streamLeftAssociativeBinaryOperator(s, precedence(), "!=", m_expr1, m_expr2); -} - -void StrictEqualNode::streamTo(SourceStream& s) const -{ - streamLeftAssociativeBinaryOperator(s, precedence(), "===", m_expr1, m_expr2); -} - -void NotStrictEqualNode::streamTo(SourceStream& s) const -{ - streamLeftAssociativeBinaryOperator(s, precedence(), "!==", m_expr1, m_expr2); -} - -void BitAndNode::streamTo(SourceStream& s) const -{ - streamLeftAssociativeBinaryOperator(s, precedence(), "&", m_expr1, m_expr2); -} - -void BitXOrNode::streamTo(SourceStream& s) const -{ - streamLeftAssociativeBinaryOperator(s, precedence(), "^", m_expr1, m_expr2); -} - -void BitOrNode::streamTo(SourceStream& s) const -{ - streamLeftAssociativeBinaryOperator(s, precedence(), "|", m_expr1, m_expr2); -} - -void LogicalOpNode::streamTo(SourceStream& s) const -{ - streamLeftAssociativeBinaryOperator(s, precedence(), (m_operator == OpLogicalAnd) ? "&&" : "||", m_expr1, m_expr2); -} - -void ConditionalNode::streamTo(SourceStream& s) const -{ - s << PrecLogicalOr << m_logical - << " ? " << PrecAssignment << m_expr1 - << " : " << PrecAssignment << m_expr2; -} - -void ReadModifyResolveNode::streamTo(SourceStream& s) const -{ - s << m_ident << ' ' << operatorString(m_operator) << ' ' << PrecAssignment << m_right; -} - -void AssignResolveNode::streamTo(SourceStream& s) const -{ - s << m_ident << " = " << PrecAssignment << m_right; -} - -void ReadModifyBracketNode::streamTo(SourceStream& s) const -{ - bracketNodeStreamTo(s, m_base, m_subscript); - s << ' ' << operatorString(m_operator) << ' ' << PrecAssignment << m_right; -} - -void AssignBracketNode::streamTo(SourceStream& s) const -{ - bracketNodeStreamTo(s, m_base, m_subscript); - s << " = " << PrecAssignment << m_right; -} - -void ReadModifyDotNode::streamTo(SourceStream& s) const -{ - dotNodeStreamTo(s, m_base, m_ident); - s << ' ' << operatorString(m_operator) << ' ' << PrecAssignment << m_right; -} - -void AssignDotNode::streamTo(SourceStream& s) const -{ - dotNodeStreamTo(s, m_base, m_ident); - s << " = " << PrecAssignment << m_right; -} - -void AssignErrorNode::streamTo(SourceStream& s) const -{ - s << PrecLeftHandSide << m_left << ' ' - << operatorString(m_operator) << ' ' << PrecAssignment << m_right; -} - -void CommaNode::streamTo(SourceStream& s) const -{ - s << PrecAssignment << m_expr1 << ", " << PrecAssignment << m_expr2; -} - -void ConstDeclNode::streamTo(SourceStream& s) const -{ - s << m_ident; - if (m_init) - s << " = " << PrecAssignment << m_init; - for (ConstDeclNode* n = m_next.get(); n; n = n->m_next.get()) { - s << ", " << n->m_ident; - if (n->m_init) - s << " = " << PrecAssignment << n->m_init; - } -} - -void ConstStatementNode::streamTo(SourceStream& s) const -{ - s << Endl << "const " << m_next << ';'; -} - -static inline void statementListStreamTo(const Vector<RefPtr<StatementNode> >& nodes, SourceStream& s) -{ - for (Vector<RefPtr<StatementNode> >::const_iterator ptr = nodes.begin(); ptr != nodes.end(); ptr++) - s << *ptr; -} - -void BlockNode::streamTo(SourceStream& s) const -{ - s << Endl << "{" << Indent; - statementListStreamTo(m_children, s); - s << Unindent << Endl << "}"; -} - -void ScopeNode::streamTo(SourceStream& s) const -{ - s << Endl << "{" << Indent; - - bool printedVar = false; - for (size_t i = 0; i < m_varStack.size(); ++i) { - if (m_varStack[i].second == 0) { - if (!printedVar) { - s << Endl << "var "; - printedVar = true; - } else - s << ", "; - s << m_varStack[i].first; - } - } - if (printedVar) - s << ';'; - - statementListStreamTo(m_children, s); - s << Unindent << Endl << "}"; -} - -void EmptyStatementNode::streamTo(SourceStream& s) const -{ - s << Endl << ';'; -} - -void DebuggerStatementNode::streamTo(SourceStream& s) const -{ - s << Endl << "debugger;"; -} - -void ExprStatementNode::streamTo(SourceStream& s) const -{ - s << Endl << m_expr << ';'; -} - -void VarStatementNode::streamTo(SourceStream& s) const -{ - s << Endl << "var " << m_expr << ';'; -} - -void IfNode::streamTo(SourceStream& s) const -{ - s << Endl << "if (" << m_condition << ')' << Indent << m_ifBlock << Unindent; -} - -void IfElseNode::streamTo(SourceStream& s) const -{ - IfNode::streamTo(s); - s << Endl << "else" << Indent << m_elseBlock << Unindent; -} - -void DoWhileNode::streamTo(SourceStream& s) const -{ - s << Endl << "do " << Indent << m_statement << Unindent << Endl - << "while (" << m_expr << ");"; -} - -void WhileNode::streamTo(SourceStream& s) const -{ - s << Endl << "while (" << m_expr << ')' << Indent << m_statement << Unindent; -} - -void ForNode::streamTo(SourceStream& s) const -{ - s << Endl << "for (" - << (m_expr1WasVarDecl ? "var " : "") - << m_expr1 - << "; " << m_expr2 - << "; " << m_expr3 - << ')' << Indent << m_statement << Unindent; -} - -void ForInNode::streamTo(SourceStream& s) const -{ - s << Endl << "for ("; - if (m_identIsVarDecl) { - s << "var "; - if (m_init) - s << m_init; - else - s << PrecLeftHandSide << m_lexpr; - } else - s << PrecLeftHandSide << m_lexpr; - - s << " in " << m_expr << ')' << Indent << m_statement << Unindent; -} - -void ContinueNode::streamTo(SourceStream& s) const -{ - s << Endl << "continue"; - if (!m_ident.isNull()) - s << ' ' << m_ident; - s << ';'; -} - -void BreakNode::streamTo(SourceStream& s) const -{ - s << Endl << "break"; - if (!m_ident.isNull()) - s << ' ' << m_ident; - s << ';'; -} - -void ReturnNode::streamTo(SourceStream& s) const -{ - s << Endl << "return"; - if (m_value) - s << ' ' << m_value; - s << ';'; -} - -void WithNode::streamTo(SourceStream& s) const -{ - s << Endl << "with (" << m_expr << ") " << m_statement; -} - -void CaseClauseNode::streamTo(SourceStream& s) const -{ - s << Endl; - if (m_expr) - s << "case " << m_expr; - else - s << "default"; - s << ":" << Indent; - statementListStreamTo(m_children, s); - s << Unindent; -} - -void ClauseListNode::streamTo(SourceStream& s) const -{ - for (const ClauseListNode* n = this; n; n = n->getNext()) - s << n->getClause(); -} - -void CaseBlockNode::streamTo(SourceStream& s) const -{ - for (const ClauseListNode* n = m_list1.get(); n; n = n->getNext()) - s << n->getClause(); - s << m_defaultClause; - for (const ClauseListNode* n = m_list2.get(); n; n = n->getNext()) - s << n->getClause(); -} - -void SwitchNode::streamTo(SourceStream& s) const -{ - s << Endl << "switch (" << m_expr << ") {" - << Indent << m_block << Unindent - << Endl << "}"; -} - -void LabelNode::streamTo(SourceStream& s) const -{ - s << Endl << m_name << ":" << Indent << m_statement << Unindent; -} - -void ThrowNode::streamTo(SourceStream& s) const -{ - s << Endl << "throw " << m_expr << ';'; -} - -void TryNode::streamTo(SourceStream& s) const -{ - s << Endl << "try " << m_tryBlock; - if (m_catchBlock) - s << Endl << "catch (" << m_exceptionIdent << ')' << m_catchBlock; - if (m_finallyBlock) - s << Endl << "finally " << m_finallyBlock; -} - -void ParameterNode::streamTo(SourceStream& s) const -{ - s << m_ident; - for (ParameterNode* n = m_next.get(); n; n = n->m_next.get()) - s << ", " << n->m_ident; -} - -void FuncDeclNode::streamTo(SourceStream& s) const -{ - s << Endl << "function " << m_ident << '(' << m_parameter << ')' << m_body; -} - -void FuncExprNode::streamTo(SourceStream& s) const -{ - s << "function " << m_ident << '(' << m_parameter << ')' << m_body; -} - -} // namespace JSC diff --git a/JavaScriptCore/kjs/operations.cpp b/JavaScriptCore/kjs/operations.cpp deleted file mode 100644 index f2d8deb..0000000 --- a/JavaScriptCore/kjs/operations.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2008 Apple Inc. All Rights Reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "operations.h" - -#include "Error.h" -#include "JSObject.h" -#include "JSString.h" -#include <math.h> -#include <stdio.h> -#include <wtf/MathExtras.h> - -#if HAVE(FLOAT_H) -#include <float.h> -#endif - -namespace JSC { - -// ECMA 11.9.3 -bool equal(ExecState* exec, JSValue* v1, JSValue* v2) -{ - if (JSImmediate::areBothImmediateNumbers(v1, v2)) - return v1 == v2; - - return equalSlowCaseInline(exec, v1, v2); -} - -bool equalSlowCase(ExecState* exec, JSValue* v1, JSValue* v2) -{ - return equalSlowCaseInline(exec, v1, v2); -} - -bool strictEqual(JSValue* v1, JSValue* v2) -{ - if (JSImmediate::areBothImmediate(v1, v2)) - return v1 == v2; - - if (JSImmediate::isEitherImmediate(v1, v2) & (v1 != JSImmediate::from(0)) & (v2 != JSImmediate::from(0))) - return false; - - return strictEqualSlowCaseInline(v1, v2); -} - -bool strictEqualSlowCase(JSValue* v1, JSValue* v2) -{ - return strictEqualSlowCaseInline(v1, v2); -} - -NEVER_INLINE JSValue* throwOutOfMemoryError(ExecState* exec) -{ - JSObject* error = Error::create(exec, GeneralError, "Out of memory"); - exec->setException(error); - return error; -} - -} // namespace JSC diff --git a/JavaScriptCore/kjs/operations.h b/JavaScriptCore/kjs/operations.h deleted file mode 100644 index fad9720..0000000 --- a/JavaScriptCore/kjs/operations.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * This file is part of the KDE libraries - * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#ifndef _KJS_OPERATIONS_H_ -#define _KJS_OPERATIONS_H_ - -#include "JSImmediate.h" -#include "JSNumberCell.h" -#include "JSString.h" - -namespace JSC { - - // ECMA 11.9.3 - bool equal(ExecState*, JSValue*, JSValue*); - bool equalSlowCase(ExecState*, JSValue*, JSValue*); - - ALWAYS_INLINE bool equalSlowCaseInline(ExecState* exec, JSValue* v1, JSValue* v2) - { - ASSERT(!JSImmediate::areBothImmediateNumbers(v1, v2)); - - do { - if (v1->isNumber() && v2->isNumber()) - return v1->uncheckedGetNumber() == v2->uncheckedGetNumber(); - - bool s1 = v1->isString(); - bool s2 = v2->isString(); - if (s1 && s2) - return asString(v1)->value() == asString(v2)->value(); - - if (v1->isUndefinedOrNull()) { - if (v2->isUndefinedOrNull()) - return true; - if (JSImmediate::isImmediate(v2)) - return false; - return v2->asCell()->structureID()->typeInfo().masqueradesAsUndefined(); - } - - if (v2->isUndefinedOrNull()) { - if (JSImmediate::isImmediate(v1)) - return false; - return v1->asCell()->structureID()->typeInfo().masqueradesAsUndefined(); - } - - if (v1->isObject()) { - if (v2->isObject()) - return v1 == v2; - JSValue* p1 = v1->toPrimitive(exec); - if (exec->hadException()) - return false; - v1 = p1; - if (JSImmediate::areBothImmediateNumbers(v1, v2)) - return v1 == v2; - continue; - } - - if (v2->isObject()) { - JSValue* p2 = v2->toPrimitive(exec); - if (exec->hadException()) - return false; - v2 = p2; - if (JSImmediate::areBothImmediateNumbers(v1, v2)) - return v1 == v2; - continue; - } - - if (s1 || s2) { - double d1 = v1->toNumber(exec); - double d2 = v2->toNumber(exec); - return d1 == d2; - } - - if (v1->isBoolean()) { - if (v2->isNumber()) - return static_cast<double>(v1->getBoolean()) == v2->uncheckedGetNumber(); - } else if (v2->isBoolean()) { - if (v1->isNumber()) - return v1->uncheckedGetNumber() == static_cast<double>(v2->getBoolean()); - } - - return v1 == v2; - } while (true); - } - - - bool strictEqual(JSValue*, JSValue*); - bool strictEqualSlowCase(JSValue*, JSValue*); - - inline bool strictEqualSlowCaseInline(JSValue* v1, JSValue* v2) - { - ASSERT(!JSImmediate::areBothImmediate(v1, v2)); - - if (JSImmediate::isEitherImmediate(v1, v2)) { - ASSERT(v1 == JSImmediate::zeroImmediate() || v2 == JSImmediate::zeroImmediate()); - ASSERT(v1 != v2); - - // The reason we can't just return false here is that 0 === -0, - // and while the former is an immediate number, the latter is not. - if (v1 == JSImmediate::zeroImmediate()) - return asCell(v2)->isNumber() && asNumberCell(v2)->value() == 0; - return asCell(v1)->isNumber() && asNumberCell(v1)->value() == 0; - } - - if (asCell(v1)->isNumber()) { - return asCell(v2)->isNumber() - && asNumberCell(v1)->value() == asNumberCell(v2)->value(); - } - - if (asCell(v1)->isString()) { - return asCell(v2)->isString() - && asString(v1)->value() == asString(v2)->value(); - } - - return v1 == v2; - } - - JSValue* throwOutOfMemoryError(ExecState*); -} - -#endif diff --git a/JavaScriptCore/kjs/protect.h b/JavaScriptCore/kjs/protect.h deleted file mode 100644 index b317424..0000000 --- a/JavaScriptCore/kjs/protect.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2004, 2008 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - - -#ifndef protect_h -#define protect_h - -#include "JSCell.h" -#include "collector.h" - -namespace JSC { - - inline void gcProtect(JSCell* val) - { - Heap::heap(val)->protect(val); - } - - inline void gcUnprotect(JSCell* val) - { - Heap::heap(val)->unprotect(val); - } - - inline void gcProtectNullTolerant(JSCell* val) - { - if (val) - gcProtect(val); - } - - inline void gcUnprotectNullTolerant(JSCell* val) - { - if (val) - gcUnprotect(val); - } - - inline void gcProtect(JSValue* value) - { - if (JSImmediate::isImmediate(value)) - return; - gcProtect(asCell(value)); - } - - inline void gcUnprotect(JSValue* value) - { - if (JSImmediate::isImmediate(value)) - return; - gcUnprotect(asCell(value)); - } - - inline void gcProtectNullTolerant(JSValue* value) - { - if (!value || JSImmediate::isImmediate(value)) - return; - gcProtect(asCell(value)); - } - - inline void gcUnprotectNullTolerant(JSValue* value) - { - if (!value || JSImmediate::isImmediate(value)) - return; - gcUnprotect(asCell(value)); - } - - // FIXME: Share more code with RefPtr template? The only differences are the ref/deref operation - // and the implicit conversion to raw pointer - template <class T> class ProtectedPtr { - public: - ProtectedPtr() : m_ptr(0) { } - ProtectedPtr(T* ptr); - ProtectedPtr(const ProtectedPtr&); - ~ProtectedPtr(); - - template <class U> ProtectedPtr(const ProtectedPtr<U>&); - - T* get() const { return m_ptr; } - operator T*() const { return m_ptr; } - T* operator->() const { return m_ptr; } - - bool operator!() const { return !m_ptr; } - - ProtectedPtr& operator=(const ProtectedPtr&); - ProtectedPtr& operator=(T*); - - private: - T* m_ptr; - }; - - template <class T> ProtectedPtr<T>::ProtectedPtr(T* ptr) - : m_ptr(ptr) - { - gcProtectNullTolerant(m_ptr); - } - - template <class T> ProtectedPtr<T>::ProtectedPtr(const ProtectedPtr& o) - : m_ptr(o.get()) - { - gcProtectNullTolerant(m_ptr); - } - - template <class T> ProtectedPtr<T>::~ProtectedPtr() - { - gcUnprotectNullTolerant(m_ptr); - } - - template <class T> template <class U> ProtectedPtr<T>::ProtectedPtr(const ProtectedPtr<U>& o) - : m_ptr(o.get()) - { - gcProtectNullTolerant(m_ptr); - } - - template <class T> ProtectedPtr<T>& ProtectedPtr<T>::operator=(const ProtectedPtr<T>& o) - { - T* optr = o.m_ptr; - gcProtectNullTolerant(optr); - gcUnprotectNullTolerant(m_ptr); - m_ptr = optr; - return *this; - } - - template <class T> inline ProtectedPtr<T>& ProtectedPtr<T>::operator=(T* optr) - { - gcProtectNullTolerant(optr); - gcUnprotectNullTolerant(m_ptr); - m_ptr = optr; - return *this; - } - - template <class T> inline bool operator==(const ProtectedPtr<T>& a, const ProtectedPtr<T>& b) { return a.get() == b.get(); } - template <class T> inline bool operator==(const ProtectedPtr<T>& a, const T* b) { return a.get() == b; } - template <class T> inline bool operator==(const T* a, const ProtectedPtr<T>& b) { return a == b.get(); } - - template <class T> inline bool operator!=(const ProtectedPtr<T>& a, const ProtectedPtr<T>& b) { return a.get() != b.get(); } - template <class T> inline bool operator!=(const ProtectedPtr<T>& a, const T* b) { return a.get() != b; } - template <class T> inline bool operator!=(const T* a, const ProtectedPtr<T>& b) { return a != b.get(); } - -} // namespace JSC - -#endif // protect_h diff --git a/JavaScriptCore/kjs/regexp.cpp b/JavaScriptCore/kjs/regexp.cpp deleted file mode 100644 index 7397232..0000000 --- a/JavaScriptCore/kjs/regexp.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (C) 1999-2001, 2004 Harri Porten (porten@kde.org) - * Copyright (c) 2007, 2008 Apple Inc. 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 - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "config.h" -#include "regexp.h" - -#include "CTI.h" -#include "lexer.h" -#include <pcre/pcre.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <wrec/WREC.h> -#include <wtf/Assertions.h> -#include <wtf/OwnArrayPtr.h> - -namespace JSC { - -inline RegExp::RegExp(JSGlobalData* globalData, const UString& pattern) - : m_pattern(pattern) - , m_flagBits(0) - , m_regExp(0) - , m_constructionError(0) - , m_numSubpatterns(0) -{ -#if ENABLE(WREC) - m_wrecFunction = CTI::compileRegExp(globalData->machine, pattern, &m_numSubpatterns, &m_constructionError); - if (m_wrecFunction) - return; - // Fall through to non-WREC case. -#else - UNUSED_PARAM(globalData); -#endif - m_regExp = jsRegExpCompile(reinterpret_cast<const UChar*>(pattern.data()), pattern.size(), - JSRegExpDoNotIgnoreCase, JSRegExpSingleLine, &m_numSubpatterns, &m_constructionError); -} - -PassRefPtr<RegExp> RegExp::create(JSGlobalData* globalData, const UString& pattern) -{ - return adoptRef(new RegExp(globalData, pattern)); -} - -inline RegExp::RegExp(JSGlobalData* globalData, const UString& pattern, const UString& flags) - : m_pattern(pattern) - , m_flags(flags) - , m_flagBits(0) - , m_regExp(0) - , m_constructionError(0) - , m_numSubpatterns(0) -{ - // NOTE: The global flag is handled on a case-by-case basis by functions like - // String::match and RegExpObject::match. - if (flags.find('g') != -1) - m_flagBits |= Global; - - // FIXME: Eliminate duplication by adding a way ask a JSRegExp what its flags are? - JSRegExpIgnoreCaseOption ignoreCaseOption = JSRegExpDoNotIgnoreCase; - if (flags.find('i') != -1) { - m_flagBits |= IgnoreCase; - ignoreCaseOption = JSRegExpIgnoreCase; - } - - JSRegExpMultilineOption multilineOption = JSRegExpSingleLine; - if (flags.find('m') != -1) { - m_flagBits |= Multiline; - multilineOption = JSRegExpMultiline; - } - -#if ENABLE(WREC) - m_wrecFunction = CTI::compileRegExp(globalData->machine, pattern, &m_numSubpatterns, &m_constructionError, (m_flagBits & IgnoreCase), (m_flagBits & Multiline)); - if (m_wrecFunction) - return; - // Fall through to non-WREC case. -#else - UNUSED_PARAM(globalData); -#endif - m_regExp = jsRegExpCompile(reinterpret_cast<const UChar*>(pattern.data()), pattern.size(), - ignoreCaseOption, multilineOption, &m_numSubpatterns, &m_constructionError); -} - -PassRefPtr<RegExp> RegExp::create(JSGlobalData* globalData, const UString& pattern, const UString& flags) -{ - return adoptRef(new RegExp(globalData, pattern, flags)); -} - -RegExp::~RegExp() -{ - jsRegExpFree(m_regExp); -#if ENABLE(WREC) - if (m_wrecFunction) - WTF::fastFreeExecutable(m_wrecFunction); -#endif -} - -int RegExp::match(const UString& s, int i, OwnArrayPtr<int>* ovector) -{ - if (i < 0) - i = 0; - if (ovector) - ovector->clear(); - - if (i > s.size() || s.isNull()) - return -1; - -#if ENABLE(WREC) - if (m_wrecFunction) { - int offsetVectorSize = (m_numSubpatterns + 1) * 2; - int* offsetVector = new int [offsetVectorSize]; - for (int j = 0; j < offsetVectorSize; ++j) - offsetVector[j] = -1; - - OwnArrayPtr<int> nonReturnedOvector; - if (!ovector) - nonReturnedOvector.set(offsetVector); - else - ovector->set(offsetVector); - - int result = reinterpret_cast<WRECFunction>(m_wrecFunction)(s.data(), i, s.size(), offsetVector); - - if (result < 0) { -#ifndef NDEBUG - // TODO: define up a symbol, rather than magic -1 - if (result != -1) - fprintf(stderr, "jsRegExpExecute failed with result %d\n", result); -#endif - if (ovector) - ovector->clear(); - } - return result; - } else -#endif - if (m_regExp) { - // Set up the offset vector for the result. - // First 2/3 used for result, the last third used by PCRE. - int* offsetVector; - int offsetVectorSize; - int fixedSizeOffsetVector[3]; - if (!ovector) { - offsetVectorSize = 3; - offsetVector = fixedSizeOffsetVector; - } else { - offsetVectorSize = (m_numSubpatterns + 1) * 3; - offsetVector = new int [offsetVectorSize]; - ovector->set(offsetVector); - } - - int numMatches = jsRegExpExecute(m_regExp, reinterpret_cast<const UChar*>(s.data()), s.size(), i, offsetVector, offsetVectorSize); - - if (numMatches < 0) { -#ifndef NDEBUG - if (numMatches != JSRegExpErrorNoMatch) - fprintf(stderr, "jsRegExpExecute failed with result %d\n", numMatches); -#endif - if (ovector) - ovector->clear(); - return -1; - } - - return offsetVector[0]; - } - - return -1; -} - -} // namespace JSC diff --git a/JavaScriptCore/kjs/regexp.h b/JavaScriptCore/kjs/regexp.h deleted file mode 100644 index 1842d94..0000000 --- a/JavaScriptCore/kjs/regexp.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2007, 2008 Apple Inc. 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 - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef KJS_REGEXP_H -#define KJS_REGEXP_H - -#include "ustring.h" -#include <wtf/Forward.h> -#include <wtf/RefCounted.h> - -struct JSRegExp; - -namespace JSC { - - class JSGlobalData; - - class RegExp : public RefCounted<RegExp> { - public: - static PassRefPtr<RegExp> create(JSGlobalData*, const UString& pattern); - static PassRefPtr<RegExp> create(JSGlobalData*, const UString& pattern, const UString& flags); - ~RegExp(); - - bool global() const { return m_flagBits & Global; } - bool ignoreCase() const { return m_flagBits & IgnoreCase; } - bool multiline() const { return m_flagBits & Multiline; } - - const UString& pattern() const { return m_pattern; } - const UString& flags() const { return m_flags; } - - bool isValid() const { return !m_constructionError; } - const char* errorMessage() const { return m_constructionError; } - - int match(const UString&, int offset, OwnArrayPtr<int>* ovector = 0); - unsigned numSubpatterns() const { return m_numSubpatterns; } - - private: - RegExp(JSGlobalData*, const UString& pattern); - RegExp(JSGlobalData*, const UString& pattern, const UString& flags); - - void compile(); - - enum FlagBits { Global = 1, IgnoreCase = 2, Multiline = 4 }; - - UString m_pattern; // FIXME: Just decompile m_regExp instead of storing this. - UString m_flags; // FIXME: Just decompile m_regExp instead of storing this. - int m_flagBits; - JSRegExp* m_regExp; - const char* m_constructionError; - unsigned m_numSubpatterns; - -#if ENABLE(WREC) - // Called as a WRECFunction - void* m_wrecFunction; -#endif - }; - -} // namespace JSC - -#endif // KJS_REGEXP_H diff --git a/JavaScriptCore/kjs/ustring.cpp b/JavaScriptCore/kjs/ustring.cpp deleted file mode 100644 index 3a85b1d..0000000 --- a/JavaScriptCore/kjs/ustring.cpp +++ /dev/null @@ -1,1638 +0,0 @@ -/* - * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "ustring.h" - -#include "JSGlobalObjectFunctions.h" -#include "collector.h" -#include "dtoa.h" -#include "identifier.h" -#include "operations.h" -#include <ctype.h> -#include <float.h> -#include <limits.h> -#include <math.h> -#include <stdio.h> -#include <stdlib.h> -#include <wtf/ASCIICType.h> -#include <wtf/Assertions.h> -#include <wtf/MathExtras.h> -#include <wtf/Vector.h> -#include <wtf/unicode/UTF8.h> - -#if HAVE(STRING_H) -#include <string.h> -#endif -#if HAVE(STRINGS_H) -#include <strings.h> -#endif - -using namespace WTF; -using namespace WTF::Unicode; -using namespace std; - -// This can be tuned differently per platform by putting platform #ifs right here. -// If you don't define this macro at all, then copyChars will just call directly -// to memcpy. -#define USTRING_COPY_CHARS_INLINE_CUTOFF 20 - -namespace JSC { - -extern const double NaN; -extern const double Inf; - -static inline size_t overflowIndicator() { return std::numeric_limits<size_t>::max(); } -static inline size_t maxUChars() { return std::numeric_limits<size_t>::max() / sizeof(UChar); } - -static inline UChar* allocChars(size_t length) -{ - ASSERT(length); - if (length > maxUChars()) - return 0; - return static_cast<UChar*>(tryFastMalloc(sizeof(UChar) * length)); -} - -static inline UChar* reallocChars(UChar* buffer, size_t length) -{ - ASSERT(length); - if (length > maxUChars()) - return 0; - return static_cast<UChar*>(tryFastRealloc(buffer, sizeof(UChar) * length)); -} - -static inline void copyChars(UChar* destination, const UChar* source, unsigned numCharacters) -{ -#ifdef USTRING_COPY_CHARS_INLINE_CUTOFF - if (numCharacters <= USTRING_COPY_CHARS_INLINE_CUTOFF) { - for (unsigned i = 0; i < numCharacters; ++i) - destination[i] = source[i]; - return; - } -#endif - memcpy(destination, source, numCharacters * sizeof(UChar)); -} - -COMPILE_ASSERT(sizeof(UChar) == 2, uchar_is_2_bytes) - -CString::CString(const char* c) - : m_length(strlen(c)) - , m_data(new char[m_length + 1]) -{ - memcpy(m_data, c, m_length + 1); -} - -CString::CString(const char* c, size_t length) - : m_length(length) - , m_data(new char[length + 1]) -{ - memcpy(m_data, c, m_length); - m_data[m_length] = 0; -} - -CString::CString(const CString& b) -{ - m_length = b.m_length; - if (b.m_data) { - m_data = new char[m_length + 1]; - memcpy(m_data, b.m_data, m_length + 1); - } else - m_data = 0; -} - -CString::~CString() -{ - delete [] m_data; -} - -CString CString::adopt(char* c, size_t length) -{ - CString s; - s.m_data = c; - s.m_length = length; - return s; -} - -CString& CString::append(const CString& t) -{ - char* n; - n = new char[m_length + t.m_length + 1]; - if (m_length) - memcpy(n, m_data, m_length); - if (t.m_length) - memcpy(n + m_length, t.m_data, t.m_length); - m_length += t.m_length; - n[m_length] = 0; - - delete [] m_data; - m_data = n; - - return *this; -} - -CString& CString::operator=(const char* c) -{ - if (m_data) - delete [] m_data; - m_length = strlen(c); - m_data = new char[m_length + 1]; - memcpy(m_data, c, m_length + 1); - - return *this; -} - -CString& CString::operator=(const CString& str) -{ - if (this == &str) - return *this; - - if (m_data) - delete [] m_data; - m_length = str.m_length; - if (str.m_data) { - m_data = new char[m_length + 1]; - memcpy(m_data, str.m_data, m_length + 1); - } else - m_data = 0; - - return *this; -} - -bool operator==(const CString& c1, const CString& c2) -{ - size_t len = c1.size(); - return len == c2.size() && (len == 0 || memcmp(c1.c_str(), c2.c_str(), len) == 0); -} - -// These static strings are immutable, except for rc, whose initial value is chosen to -// reduce the possibility of it becoming zero due to ref/deref not being thread-safe. -static UChar sharedEmptyChar; -UString::Rep UString::Rep::null = { 0, 0, INT_MAX / 2, 0, 1, &UString::Rep::null, 0, 0, 0, 0, 0, 0 }; -UString::Rep UString::Rep::empty = { 0, 0, INT_MAX / 2, 0, 1, &UString::Rep::empty, 0, &sharedEmptyChar, 0, 0, 0, 0 }; - -static char* statBuffer = 0; // Only used for debugging via UString::ascii(). - -PassRefPtr<UString::Rep> UString::Rep::createCopying(const UChar* d, int l) -{ - UChar* copyD = static_cast<UChar*>(fastMalloc(l * sizeof(UChar))); - copyChars(copyD, d, l); - return create(copyD, l); -} - -PassRefPtr<UString::Rep> UString::Rep::create(UChar* d, int l) -{ - Rep* r = new Rep; - r->offset = 0; - r->len = l; - r->rc = 1; - r->_hash = 0; - r->m_identifierTable = 0; - r->baseString = r; - r->reportedCost = 0; - r->buf = d; - r->usedCapacity = l; - r->capacity = l; - r->usedPreCapacity = 0; - r->preCapacity = 0; - - r->checkConsistency(); - - // steal the single reference this Rep was created with - return adoptRef(r); -} - -PassRefPtr<UString::Rep> UString::Rep::create(PassRefPtr<Rep> base, int offset, int length) -{ - ASSERT(base); - base->checkConsistency(); - - int baseOffset = base->offset; - - base = base->baseString; - - ASSERT(-(offset + baseOffset) <= base->usedPreCapacity); - ASSERT(offset + baseOffset + length <= base->usedCapacity); - - Rep* r = new Rep; - r->offset = baseOffset + offset; - r->len = length; - r->rc = 1; - r->_hash = 0; - r->m_identifierTable = 0; - r->baseString = base.releaseRef(); - r->reportedCost = 0; - r->buf = 0; - r->usedCapacity = 0; - r->capacity = 0; - r->usedPreCapacity = 0; - r->preCapacity = 0; - - r->checkConsistency(); - - // steal the single reference this Rep was created with - return adoptRef(r); -} - -PassRefPtr<UString::Rep> UString::Rep::createFromUTF8(const char* string) -{ - if (!string) - return &UString::Rep::null; - - size_t length = strlen(string); - Vector<UChar, 1024> buffer(length); - UChar* p = buffer.data(); - if (conversionOK != convertUTF8ToUTF16(&string, string + length, &p, p + length)) - return &UString::Rep::null; - - return UString::Rep::createCopying(buffer.data(), p - buffer.data()); -} - -void UString::Rep::destroy() -{ - checkConsistency(); - - // Static null and empty strings can never be destroyed, but we cannot rely on - // reference counting, because ref/deref are not thread-safe. - if (!isStatic()) { - if (identifierTable()) - Identifier::remove(this); - if (baseString == this) - fastFree(buf); - else - baseString->deref(); - - delete this; - } -} - -// Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's -// or anything like that. -const unsigned PHI = 0x9e3779b9U; - -// Paul Hsieh's SuperFastHash -// http://www.azillionmonkeys.com/qed/hash.html -unsigned UString::Rep::computeHash(const UChar* s, int len) -{ - unsigned l = len; - uint32_t hash = PHI; - uint32_t tmp; - - int rem = l & 1; - l >>= 1; - - // Main loop - for (; l > 0; l--) { - hash += s[0]; - tmp = (s[1] << 11) ^ hash; - hash = (hash << 16) ^ tmp; - s += 2; - hash += hash >> 11; - } - - // Handle end case - if (rem) { - hash += s[0]; - hash ^= hash << 11; - hash += hash >> 17; - } - - // Force "avalanching" of final 127 bits - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 2; - hash += hash >> 15; - hash ^= hash << 10; - - // this avoids ever returning a hash code of 0, since that is used to - // signal "hash not computed yet", using a value that is likely to be - // effectively the same as 0 when the low bits are masked - if (hash == 0) - hash = 0x80000000; - - return hash; -} - -// Paul Hsieh's SuperFastHash -// http://www.azillionmonkeys.com/qed/hash.html -unsigned UString::Rep::computeHash(const char* s, int l) -{ - // This hash is designed to work on 16-bit chunks at a time. But since the normal case - // (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they - // were 16-bit chunks, which should give matching results - - uint32_t hash = PHI; - uint32_t tmp; - - size_t rem = l & 1; - l >>= 1; - - // Main loop - for (; l > 0; l--) { - hash += static_cast<unsigned char>(s[0]); - tmp = (static_cast<unsigned char>(s[1]) << 11) ^ hash; - hash = (hash << 16) ^ tmp; - s += 2; - hash += hash >> 11; - } - - // Handle end case - if (rem) { - hash += static_cast<unsigned char>(s[0]); - hash ^= hash << 11; - hash += hash >> 17; - } - - // Force "avalanching" of final 127 bits - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 2; - hash += hash >> 15; - hash ^= hash << 10; - - // this avoids ever returning a hash code of 0, since that is used to - // signal "hash not computed yet", using a value that is likely to be - // effectively the same as 0 when the low bits are masked - if (hash == 0) - hash = 0x80000000; - - return hash; -} - -#ifndef NDEBUG -void UString::Rep::checkConsistency() const -{ - // Only base strings have non-zero shared data. - if (this != baseString) { - ASSERT(!buf); - ASSERT(!usedCapacity); - ASSERT(!capacity); - ASSERT(!usedPreCapacity); - ASSERT(!preCapacity); - } - - // There is no recursion for base strings. - ASSERT(baseString == baseString->baseString); - - if (isStatic()) { - // There are only two static strings: null and empty. - ASSERT(!len); - - // Static strings cannot get in identifier tables, because they are globally shared. - ASSERT(!identifierTable()); - } - - // The string fits in buffer. - ASSERT(baseString->usedPreCapacity <= baseString->preCapacity); - ASSERT(baseString->usedCapacity <= baseString->capacity); - ASSERT(-offset <= baseString->usedPreCapacity); - ASSERT(offset + len <= baseString->usedCapacity); -} -#endif - -// put these early so they can be inlined -static inline size_t expandedSize(size_t size, size_t otherSize) -{ - // Do the size calculation in two parts, returning overflowIndicator if - // we overflow the maximum value that we can handle. - - if (size > maxUChars()) - return overflowIndicator(); - - size_t expandedSize = ((size + 10) / 10 * 11) + 1; - if (maxUChars() - expandedSize < otherSize) - return overflowIndicator(); - - return expandedSize + otherSize; -} - -inline int UString::usedCapacity() const -{ - return m_rep->baseString->usedCapacity; -} - -inline int UString::usedPreCapacity() const -{ - return m_rep->baseString->usedPreCapacity; -} - - -static inline bool expandCapacity(UString::Rep* rep, int requiredLength) -{ - rep->checkConsistency(); - - UString::Rep* r = rep->baseString; - - if (requiredLength > r->capacity) { - size_t newCapacity = expandedSize(requiredLength, r->preCapacity); - UChar* oldBuf = r->buf; - r->buf = reallocChars(r->buf, newCapacity); - if (!r->buf) { - r->buf = oldBuf; - return false; - } - r->capacity = newCapacity - r->preCapacity; - } - if (requiredLength > r->usedCapacity) - r->usedCapacity = requiredLength; - - rep->checkConsistency(); - return true; -} - -void UString::expandCapacity(int requiredLength) -{ - if (!JSC::expandCapacity(m_rep.get(), requiredLength)) - makeNull(); -} - -void UString::expandPreCapacity(int requiredPreCap) -{ - m_rep->checkConsistency(); - - Rep* r = m_rep->baseString; - - if (requiredPreCap > r->preCapacity) { - size_t newCapacity = expandedSize(requiredPreCap, r->capacity); - int delta = newCapacity - r->capacity - r->preCapacity; - - UChar* newBuf = allocChars(newCapacity); - if (!newBuf) { - makeNull(); - return; - } - copyChars(newBuf + delta, r->buf, r->capacity + r->preCapacity); - fastFree(r->buf); - r->buf = newBuf; - - r->preCapacity = newCapacity - r->capacity; - } - if (requiredPreCap > r->usedPreCapacity) - r->usedPreCapacity = requiredPreCap; - - m_rep->checkConsistency(); -} - -PassRefPtr<UString::Rep> createRep(const char* c) -{ - if (!c) - return &UString::Rep::null; - - if (!c[0]) - return &UString::Rep::empty; - - size_t length = strlen(c); - UChar* d = allocChars(length); - if (!d) - return &UString::Rep::null; - else { - for (size_t i = 0; i < length; i++) - d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend - return UString::Rep::create(d, static_cast<int>(length)); - } - -} - -UString::UString(const char* c) - : m_rep(createRep(c)) -{ -} - -UString::UString(const UChar* c, int length) -{ - if (length == 0) - m_rep = &Rep::empty; - else - m_rep = Rep::createCopying(c, length); -} - -UString::UString(UChar* c, int length, bool copy) -{ - if (length == 0) - m_rep = &Rep::empty; - else if (copy) - m_rep = Rep::createCopying(c, length); - else - m_rep = Rep::create(c, length); -} - -UString::UString(const Vector<UChar>& buffer) -{ - if (!buffer.size()) - m_rep = &Rep::empty; - else - m_rep = Rep::createCopying(buffer.data(), buffer.size()); -} - -static ALWAYS_INLINE PassRefPtr<UString::Rep> concatenate(PassRefPtr<UString::Rep> r, const UChar* tData, int tSize) -{ - RefPtr<UString::Rep> rep = r; - - rep->checkConsistency(); - - int thisSize = rep->size(); - int thisOffset = rep->offset; - int length = thisSize + tSize; - - // possible cases: - if (tSize == 0) { - // t is empty - } else if (thisSize == 0) { - // this is empty - rep = UString::Rep::createCopying(tData, tSize); - } else if (rep->baseIsSelf() && rep->rc == 1) { - // this is direct and has refcount of 1 (so we can just alter it directly) - if (!expandCapacity(rep.get(), thisOffset + length)) - rep = &UString::Rep::null; - if (rep->data()) { - copyChars(rep->data() + thisSize, tData, tSize); - rep->len = length; - rep->_hash = 0; - } - } else if (thisOffset + thisSize == rep->baseString->usedCapacity && thisSize >= minShareSize) { - // this reaches the end of the buffer - extend it if it's long enough to append to - if (!expandCapacity(rep.get(), thisOffset + length)) - rep = &UString::Rep::null; - if (rep->data()) { - copyChars(rep->data() + thisSize, tData, tSize); - rep = UString::Rep::create(rep, 0, length); - } - } else { - // this is shared with someone using more capacity, gotta make a whole new string - size_t newCapacity = expandedSize(length, 0); - UChar* d = allocChars(newCapacity); - if (!d) - rep = &UString::Rep::null; - else { - copyChars(d, rep->data(), thisSize); - copyChars(d + thisSize, tData, tSize); - rep = UString::Rep::create(d, length); - rep->capacity = newCapacity; - } - } - - rep->checkConsistency(); - - return rep.release(); -} - -static ALWAYS_INLINE PassRefPtr<UString::Rep> concatenate(PassRefPtr<UString::Rep> r, const char* t) -{ - RefPtr<UString::Rep> rep = r; - - rep->checkConsistency(); - - int thisSize = rep->size(); - int thisOffset = rep->offset; - int tSize = static_cast<int>(strlen(t)); - int length = thisSize + tSize; - - // possible cases: - if (thisSize == 0) { - // this is empty - rep = createRep(t); - } else if (tSize == 0) { - // t is empty, we'll just return *this below. - } else if (rep->baseIsSelf() && rep->rc == 1) { - // this is direct and has refcount of 1 (so we can just alter it directly) - expandCapacity(rep.get(), thisOffset + length); - UChar* d = rep->data(); - if (d) { - for (int i = 0; i < tSize; ++i) - d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend - rep->len = length; - rep->_hash = 0; - } - } else if (thisOffset + thisSize == rep->baseString->usedCapacity && thisSize >= minShareSize) { - // this string reaches the end of the buffer - extend it - expandCapacity(rep.get(), thisOffset + length); - UChar* d = rep->data(); - if (d) { - for (int i = 0; i < tSize; ++i) - d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend - rep = UString::Rep::create(rep, 0, length); - } - } else { - // this is shared with someone using more capacity, gotta make a whole new string - size_t newCapacity = expandedSize(length, 0); - UChar* d = allocChars(newCapacity); - if (!d) - rep = &UString::Rep::null; - else { - copyChars(d, rep->data(), thisSize); - for (int i = 0; i < tSize; ++i) - d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend - rep = UString::Rep::create(d, length); - rep->capacity = newCapacity; - } - } - - rep->checkConsistency(); - - return rep.release(); -} - -PassRefPtr<UString::Rep> concatenate(UString::Rep* a, UString::Rep* b) -{ - a->checkConsistency(); - b->checkConsistency(); - - int aSize = a->size(); - int aOffset = a->offset; - int bSize = b->size(); - int bOffset = b->offset; - int length = aSize + bSize; - - // possible cases: - - // a is empty - if (aSize == 0) - return b; - // b is empty - if (bSize == 0) - return a; - - if (bSize == 1 && aOffset + aSize == a->baseString->usedCapacity && aOffset + length <= a->baseString->capacity) { - // b is a single character (common fast case) - a->baseString->usedCapacity = aOffset + length; - a->data()[aSize] = b->data()[0]; - return UString::Rep::create(a, 0, length); - } - - if (aOffset + aSize == a->baseString->usedCapacity && aSize >= minShareSize && 4 * aSize >= bSize && - (-bOffset != b->baseString->usedPreCapacity || aSize >= bSize)) { - // - a reaches the end of its buffer so it qualifies for shared append - // - also, it's at least a quarter the length of b - appending to a much shorter - // string does more harm than good - // - however, if b qualifies for prepend and is longer than a, we'd rather prepend - UString x(a); - x.expandCapacity(aOffset + length); - if (!a->data() || !x.data()) - return 0; - copyChars(a->data() + aSize, b->data(), bSize); - PassRefPtr<UString::Rep> result = UString::Rep::create(a, 0, length); - - a->checkConsistency(); - b->checkConsistency(); - result->checkConsistency(); - - return result; - } - - if (-bOffset == b->baseString->usedPreCapacity && bSize >= minShareSize && 4 * bSize >= aSize) { - // - b reaches the beginning of its buffer so it qualifies for shared prepend - // - also, it's at least a quarter the length of a - prepending to a much shorter - // string does more harm than good - UString y(b); - y.expandPreCapacity(-bOffset + aSize); - if (!b->data() || !y.data()) - return 0; - copyChars(b->data() - aSize, a->data(), aSize); - PassRefPtr<UString::Rep> result = UString::Rep::create(b, -aSize, length); - - a->checkConsistency(); - b->checkConsistency(); - result->checkConsistency(); - - return result; - } - - // a does not qualify for append, and b does not qualify for prepend, gotta make a whole new string - size_t newCapacity = expandedSize(length, 0); - UChar* d = allocChars(newCapacity); - if (!d) - return 0; - copyChars(d, a->data(), aSize); - copyChars(d + aSize, b->data(), bSize); - PassRefPtr<UString::Rep> result = UString::Rep::create(d, length); - result->capacity = newCapacity; - - a->checkConsistency(); - b->checkConsistency(); - result->checkConsistency(); - - return result; -} - -PassRefPtr<UString::Rep> concatenate(UString::Rep* rep, int i) -{ - UChar buf[1 + sizeof(i) * 3]; - UChar* end = buf + sizeof(buf) / sizeof(UChar); - UChar* p = end; - - if (i == 0) - *--p = '0'; - else if (i == INT_MIN) { - char minBuf[1 + sizeof(i) * 3]; - sprintf(minBuf, "%d", INT_MIN); - return concatenate(rep, minBuf); - } else { - bool negative = false; - if (i < 0) { - negative = true; - i = -i; - } - while (i) { - *--p = static_cast<unsigned short>((i % 10) + '0'); - i /= 10; - } - if (negative) - *--p = '-'; - } - - return concatenate(rep, p, static_cast<int>(end - p)); - -} - -PassRefPtr<UString::Rep> concatenate(UString::Rep* rep, double d) -{ - // avoid ever printing -NaN, in JS conceptually there is only one NaN value - if (isnan(d)) - return concatenate(rep, "NaN"); - - if (d == 0.0) // stringify -0 as 0 - d = 0.0; - - char buf[80]; - int decimalPoint; - int sign; - - char* result = dtoa(d, 0, &decimalPoint, &sign, NULL); - int length = static_cast<int>(strlen(result)); - - int i = 0; - if (sign) - buf[i++] = '-'; - - if (decimalPoint <= 0 && decimalPoint > -6) { - buf[i++] = '0'; - buf[i++] = '.'; - for (int j = decimalPoint; j < 0; j++) - buf[i++] = '0'; - strcpy(buf + i, result); - } else if (decimalPoint <= 21 && decimalPoint > 0) { - if (length <= decimalPoint) { - strcpy(buf + i, result); - i += length; - for (int j = 0; j < decimalPoint - length; j++) - buf[i++] = '0'; - buf[i] = '\0'; - } else { - strncpy(buf + i, result, decimalPoint); - i += decimalPoint; - buf[i++] = '.'; - strcpy(buf + i, result + decimalPoint); - } - } else if (result[0] < '0' || result[0] > '9') - strcpy(buf + i, result); - else { - buf[i++] = result[0]; - if (length > 1) { - buf[i++] = '.'; - strcpy(buf + i, result + 1); - i += length - 1; - } - - buf[i++] = 'e'; - buf[i++] = (decimalPoint >= 0) ? '+' : '-'; - // decimalPoint can't be more than 3 digits decimal given the - // nature of float representation - int exponential = decimalPoint - 1; - if (exponential < 0) - exponential = -exponential; - if (exponential >= 100) - buf[i++] = static_cast<char>('0' + exponential / 100); - if (exponential >= 10) - buf[i++] = static_cast<char>('0' + (exponential % 100) / 10); - buf[i++] = static_cast<char>('0' + exponential % 10); - buf[i++] = '\0'; - } - - freedtoa(result); - - return concatenate(rep, buf); -} - -const UString& UString::null() -{ - static UString* n = new UString; // Should be called from main thread at least once to be safely initialized. - return *n; -} - -UString UString::from(int i) -{ - UChar buf[1 + sizeof(i) * 3]; - UChar* end = buf + sizeof(buf) / sizeof(UChar); - UChar* p = end; - - if (i == 0) - *--p = '0'; - else if (i == INT_MIN) { - char minBuf[1 + sizeof(i) * 3]; - sprintf(minBuf, "%d", INT_MIN); - return UString(minBuf); - } else { - bool negative = false; - if (i < 0) { - negative = true; - i = -i; - } - while (i) { - *--p = static_cast<unsigned short>((i % 10) + '0'); - i /= 10; - } - if (negative) - *--p = '-'; - } - - return UString(p, static_cast<int>(end - p)); -} - -UString UString::from(unsigned int u) -{ - UChar buf[sizeof(u) * 3]; - UChar* end = buf + sizeof(buf) / sizeof(UChar); - UChar* p = end; - - if (u == 0) - *--p = '0'; - else { - while (u) { - *--p = static_cast<unsigned short>((u % 10) + '0'); - u /= 10; - } - } - - return UString(p, static_cast<int>(end - p)); -} - -UString UString::from(long l) -{ - UChar buf[1 + sizeof(l) * 3]; - UChar* end = buf + sizeof(buf) / sizeof(UChar); - UChar* p = end; - - if (l == 0) - *--p = '0'; - else if (l == LONG_MIN) { - char minBuf[1 + sizeof(l) * 3]; - sprintf(minBuf, "%ld", LONG_MIN); - return UString(minBuf); - } else { - bool negative = false; - if (l < 0) { - negative = true; - l = -l; - } - while (l) { - *--p = static_cast<unsigned short>((l % 10) + '0'); - l /= 10; - } - if (negative) - *--p = '-'; - } - - return UString(p, static_cast<int>(end - p)); -} - -UString UString::from(double d) -{ - // avoid ever printing -NaN, in JS conceptually there is only one NaN value - if (isnan(d)) - return "NaN"; - - char buf[80]; - int decimalPoint; - int sign; - - char* result = dtoa(d, 0, &decimalPoint, &sign, NULL); - int length = static_cast<int>(strlen(result)); - - int i = 0; - if (sign) - buf[i++] = '-'; - - if (decimalPoint <= 0 && decimalPoint > -6) { - buf[i++] = '0'; - buf[i++] = '.'; - for (int j = decimalPoint; j < 0; j++) - buf[i++] = '0'; - strcpy(buf + i, result); - } else if (decimalPoint <= 21 && decimalPoint > 0) { - if (length <= decimalPoint) { - strcpy(buf + i, result); - i += length; - for (int j = 0; j < decimalPoint - length; j++) - buf[i++] = '0'; - buf[i] = '\0'; - } else { - strncpy(buf + i, result, decimalPoint); - i += decimalPoint; - buf[i++] = '.'; - strcpy(buf + i, result + decimalPoint); - } - } else if (result[0] < '0' || result[0] > '9') - strcpy(buf + i, result); - else { - buf[i++] = result[0]; - if (length > 1) { - buf[i++] = '.'; - strcpy(buf + i, result + 1); - i += length - 1; - } - - buf[i++] = 'e'; - buf[i++] = (decimalPoint >= 0) ? '+' : '-'; - // decimalPoint can't be more than 3 digits decimal given the - // nature of float representation - int exponential = decimalPoint - 1; - if (exponential < 0) - exponential = -exponential; - if (exponential >= 100) - buf[i++] = static_cast<char>('0' + exponential / 100); - if (exponential >= 10) - buf[i++] = static_cast<char>('0' + (exponential % 100) / 10); - buf[i++] = static_cast<char>('0' + exponential % 10); - buf[i++] = '\0'; - } - - freedtoa(result); - - return UString(buf); -} - -UString UString::spliceSubstringsWithSeparators(const Range* substringRanges, int rangeCount, const UString* separators, int separatorCount) const -{ - m_rep->checkConsistency(); - - if (rangeCount == 1 && separatorCount == 0) { - int thisSize = size(); - int position = substringRanges[0].position; - int length = substringRanges[0].length; - if (position <= 0 && length >= thisSize) - return *this; - return UString::Rep::create(m_rep, max(0, position), min(thisSize, length)); - } - - int totalLength = 0; - for (int i = 0; i < rangeCount; i++) - totalLength += substringRanges[i].length; - for (int i = 0; i < separatorCount; i++) - totalLength += separators[i].size(); - - if (totalLength == 0) - return ""; - - UChar* buffer = allocChars(totalLength); - if (!buffer) - return null(); - - int maxCount = max(rangeCount, separatorCount); - int bufferPos = 0; - for (int i = 0; i < maxCount; i++) { - if (i < rangeCount) { - copyChars(buffer + bufferPos, data() + substringRanges[i].position, substringRanges[i].length); - bufferPos += substringRanges[i].length; - } - if (i < separatorCount) { - copyChars(buffer + bufferPos, separators[i].data(), separators[i].size()); - bufferPos += separators[i].size(); - } - } - - return UString::Rep::create(buffer, totalLength); -} - -UString& UString::append(const UString &t) -{ - m_rep->checkConsistency(); - t.rep()->checkConsistency(); - - int thisSize = size(); - int thisOffset = m_rep->offset; - int tSize = t.size(); - int length = thisSize + tSize; - - // possible cases: - if (thisSize == 0) { - // this is empty - *this = t; - } else if (tSize == 0) { - // t is empty - } else if (m_rep->baseIsSelf() && m_rep->rc == 1) { - // this is direct and has refcount of 1 (so we can just alter it directly) - expandCapacity(thisOffset + length); - if (data()) { - copyChars(m_rep->data() + thisSize, t.data(), tSize); - m_rep->len = length; - m_rep->_hash = 0; - } - } else if (thisOffset + thisSize == usedCapacity() && thisSize >= minShareSize) { - // this reaches the end of the buffer - extend it if it's long enough to append to - expandCapacity(thisOffset + length); - if (data()) { - copyChars(m_rep->data() + thisSize, t.data(), tSize); - m_rep = Rep::create(m_rep, 0, length); - } - } else { - // this is shared with someone using more capacity, gotta make a whole new string - size_t newCapacity = expandedSize(length, 0); - UChar* d = allocChars(newCapacity); - if (!d) - makeNull(); - else { - copyChars(d, data(), thisSize); - copyChars(d + thisSize, t.data(), tSize); - m_rep = Rep::create(d, length); - m_rep->capacity = newCapacity; - } - } - - m_rep->checkConsistency(); - t.rep()->checkConsistency(); - - return *this; -} - -UString& UString::append(const UChar* tData, int tSize) -{ - m_rep = concatenate(m_rep.release(), tData, tSize); - return *this; -} - -UString& UString::append(const char* t) -{ - m_rep = concatenate(m_rep.release(), t); - return *this; -} - -UString& UString::append(UChar c) -{ - m_rep->checkConsistency(); - - int thisOffset = m_rep->offset; - int length = size(); - - // possible cases: - if (length == 0) { - // this is empty - must make a new m_rep because we don't want to pollute the shared empty one - size_t newCapacity = expandedSize(1, 0); - UChar* d = allocChars(newCapacity); - if (!d) - makeNull(); - else { - d[0] = c; - m_rep = Rep::create(d, 1); - m_rep->capacity = newCapacity; - } - } else if (m_rep->baseIsSelf() && m_rep->rc == 1) { - // this is direct and has refcount of 1 (so we can just alter it directly) - expandCapacity(thisOffset + length + 1); - UChar* d = m_rep->data(); - if (d) { - d[length] = c; - m_rep->len = length + 1; - m_rep->_hash = 0; - } - } else if (thisOffset + length == usedCapacity() && length >= minShareSize) { - // this reaches the end of the string - extend it and share - expandCapacity(thisOffset + length + 1); - UChar* d = m_rep->data(); - if (d) { - d[length] = c; - m_rep = Rep::create(m_rep, 0, length + 1); - } - } else { - // this is shared with someone using more capacity, gotta make a whole new string - size_t newCapacity = expandedSize(length + 1, 0); - UChar* d = allocChars(newCapacity); - if (!d) - makeNull(); - else { - copyChars(d, data(), length); - d[length] = c; - m_rep = Rep::create(d, length + 1); - m_rep->capacity = newCapacity; - } - } - - m_rep->checkConsistency(); - - return *this; -} - -bool UString::getCString(CStringBuffer& buffer) const -{ - int length = size(); - int neededSize = length + 1; - buffer.resize(neededSize); - char* buf = buffer.data(); - - UChar ored = 0; - const UChar* p = data(); - char* q = buf; - const UChar* limit = p + length; - while (p != limit) { - UChar c = p[0]; - ored |= c; - *q = static_cast<char>(c); - ++p; - ++q; - } - *q = '\0'; - - return !(ored & 0xFF00); -} - -char* UString::ascii() const -{ - int length = size(); - int neededSize = length + 1; - delete[] statBuffer; - statBuffer = new char[neededSize]; - - const UChar* p = data(); - char* q = statBuffer; - const UChar* limit = p + length; - while (p != limit) { - *q = static_cast<char>(p[0]); - ++p; - ++q; - } - *q = '\0'; - - return statBuffer; -} - -UString& UString::operator=(const char* c) -{ - if (!c) { - m_rep = &Rep::null; - return *this; - } - - if (!c[0]) { - m_rep = &Rep::empty; - return *this; - } - - int l = static_cast<int>(strlen(c)); - UChar* d; - if (m_rep->rc == 1 && l <= m_rep->capacity && m_rep->baseIsSelf() && m_rep->offset == 0 && m_rep->preCapacity == 0) { - d = m_rep->buf; - m_rep->_hash = 0; - m_rep->len = l; - } else { - d = allocChars(l); - if (!d) { - makeNull(); - return *this; - } - m_rep = Rep::create(d, l); - } - for (int i = 0; i < l; i++) - d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend - - return *this; -} - -bool UString::is8Bit() const -{ - const UChar* u = data(); - const UChar* limit = u + size(); - while (u < limit) { - if (u[0] > 0xFF) - return false; - ++u; - } - - return true; -} - -UChar UString::operator[](int pos) const -{ - if (pos >= size()) - return '\0'; - return data()[pos]; -} - -double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const -{ - if (size() == 1) { - UChar c = data()[0]; - if (isASCIIDigit(c)) - return c - '0'; - if (isASCIISpace(c) && tolerateEmptyString) - return 0; - return NaN; - } - - // FIXME: If tolerateTrailingJunk is true, then we want to tolerate non-8-bit junk - // after the number, so this is too strict a check. - CStringBuffer s; - if (!getCString(s)) - return NaN; - const char* c = s.data(); - - // skip leading white space - while (isASCIISpace(*c)) - c++; - - // empty string ? - if (*c == '\0') - return tolerateEmptyString ? 0.0 : NaN; - - double d; - - // hex number ? - if (*c == '0' && (*(c + 1) == 'x' || *(c + 1) == 'X')) { - const char* firstDigitPosition = c + 2; - c++; - d = 0.0; - while (*(++c)) { - if (*c >= '0' && *c <= '9') - d = d * 16.0 + *c - '0'; - else if ((*c >= 'A' && *c <= 'F') || (*c >= 'a' && *c <= 'f')) - d = d * 16.0 + (*c & 0xdf) - 'A' + 10.0; - else - break; - } - - if (d >= mantissaOverflowLowerBound) - d = parseIntOverflow(firstDigitPosition, c - firstDigitPosition, 16); - } else { - // regular number ? - char* end; - d = strtod(c, &end); - if ((d != 0.0 || end != c) && d != Inf && d != -Inf) { - c = end; - } else { - double sign = 1.0; - - if (*c == '+') - c++; - else if (*c == '-') { - sign = -1.0; - c++; - } - - // We used strtod() to do the conversion. However, strtod() handles - // infinite values slightly differently than JavaScript in that it - // converts the string "inf" with any capitalization to infinity, - // whereas the ECMA spec requires that it be converted to NaN. - - if (c[0] == 'I' && c[1] == 'n' && c[2] == 'f' && c[3] == 'i' && c[4] == 'n' && c[5] == 'i' && c[6] == 't' && c[7] == 'y') { - d = sign * Inf; - c += 8; - } else if ((d == Inf || d == -Inf) && *c != 'I' && *c != 'i') - c = end; - else - return NaN; - } - } - - // allow trailing white space - while (isASCIISpace(*c)) - c++; - // don't allow anything after - unless tolerant=true - if (!tolerateTrailingJunk && *c != '\0') - d = NaN; - - return d; -} - -double UString::toDouble(bool tolerateTrailingJunk) const -{ - return toDouble(tolerateTrailingJunk, true); -} - -double UString::toDouble() const -{ - return toDouble(false, true); -} - -uint32_t UString::toUInt32(bool* ok) const -{ - double d = toDouble(); - bool b = true; - - if (d != static_cast<uint32_t>(d)) { - b = false; - d = 0; - } - - if (ok) - *ok = b; - - return static_cast<uint32_t>(d); -} - -uint32_t UString::toUInt32(bool* ok, bool tolerateEmptyString) const -{ - double d = toDouble(false, tolerateEmptyString); - bool b = true; - - if (d != static_cast<uint32_t>(d)) { - b = false; - d = 0; - } - - if (ok) - *ok = b; - - return static_cast<uint32_t>(d); -} - -uint32_t UString::toStrictUInt32(bool* ok) const -{ - if (ok) - *ok = false; - - // Empty string is not OK. - int len = m_rep->len; - if (len == 0) - return 0; - const UChar* p = m_rep->data(); - unsigned short c = p[0]; - - // If the first digit is 0, only 0 itself is OK. - if (c == '0') { - if (len == 1 && ok) - *ok = true; - return 0; - } - - // Convert to UInt32, checking for overflow. - uint32_t i = 0; - while (1) { - // Process character, turning it into a digit. - if (c < '0' || c > '9') - return 0; - const unsigned d = c - '0'; - - // Multiply by 10, checking for overflow out of 32 bits. - if (i > 0xFFFFFFFFU / 10) - return 0; - i *= 10; - - // Add in the digit, checking for overflow out of 32 bits. - const unsigned max = 0xFFFFFFFFU - d; - if (i > max) - return 0; - i += d; - - // Handle end of string. - if (--len == 0) { - if (ok) - *ok = true; - return i; - } - - // Get next character. - c = *(++p); - } -} - -int UString::find(const UString& f, int pos) const -{ - int sz = size(); - int fsz = f.size(); - if (sz < fsz) - return -1; - if (pos < 0) - pos = 0; - if (fsz == 0) - return pos; - const UChar* end = data() + sz - fsz; - int fsizeminusone = (fsz - 1) * sizeof(UChar); - const UChar* fdata = f.data(); - unsigned short fchar = fdata[0]; - ++fdata; - for (const UChar* c = data() + pos; c <= end; c++) { - if (c[0] == fchar && !memcmp(c + 1, fdata, fsizeminusone)) - return static_cast<int>(c - data()); - } - - return -1; -} - -int UString::find(UChar ch, int pos) const -{ - if (pos < 0) - pos = 0; - const UChar* end = data() + size(); - for (const UChar* c = data() + pos; c < end; c++) { - if (*c == ch) - return static_cast<int>(c - data()); - } - - return -1; -} - -int UString::rfind(const UString& f, int pos) const -{ - int sz = size(); - int fsz = f.size(); - if (sz < fsz) - return -1; - if (pos < 0) - pos = 0; - if (pos > sz - fsz) - pos = sz - fsz; - if (fsz == 0) - return pos; - int fsizeminusone = (fsz - 1) * sizeof(UChar); - const UChar* fdata = f.data(); - for (const UChar* c = data() + pos; c >= data(); c--) { - if (*c == *fdata && !memcmp(c + 1, fdata + 1, fsizeminusone)) - return static_cast<int>(c - data()); - } - - return -1; -} - -int UString::rfind(UChar ch, int pos) const -{ - if (isEmpty()) - return -1; - if (pos + 1 >= size()) - pos = size() - 1; - for (const UChar* c = data() + pos; c >= data(); c--) { - if (*c == ch) - return static_cast<int>(c - data()); - } - - return -1; -} - -UString UString::substr(int pos, int len) const -{ - int s = size(); - - if (pos < 0) - pos = 0; - else if (pos >= s) - pos = s; - if (len < 0) - len = s; - if (pos + len >= s) - len = s - pos; - - if (pos == 0 && len == s) - return *this; - - return UString(Rep::create(m_rep, pos, len)); -} - -bool operator==(const UString& s1, const UString& s2) -{ - int size = s1.size(); - switch (size) { - case 0: - return !s2.size(); - case 1: - return s2.size() == 1 && s1.data()[0] == s2.data()[0]; - default: - return s2.size() == size && memcmp(s1.data(), s2.data(), size * sizeof(UChar)) == 0; - } -} - -bool operator==(const UString& s1, const char *s2) -{ - if (s2 == 0) - return s1.isEmpty(); - - const UChar* u = s1.data(); - const UChar* uend = u + s1.size(); - while (u != uend && *s2) { - if (u[0] != (unsigned char)*s2) - return false; - s2++; - u++; - } - - return u == uend && *s2 == 0; -} - -bool operator<(const UString& s1, const UString& s2) -{ - const int l1 = s1.size(); - const int l2 = s2.size(); - const int lmin = l1 < l2 ? l1 : l2; - const UChar* c1 = s1.data(); - const UChar* c2 = s2.data(); - int l = 0; - while (l < lmin && *c1 == *c2) { - c1++; - c2++; - l++; - } - if (l < lmin) - return (c1[0] < c2[0]); - - return (l1 < l2); -} - -bool operator>(const UString& s1, const UString& s2) -{ - const int l1 = s1.size(); - const int l2 = s2.size(); - const int lmin = l1 < l2 ? l1 : l2; - const UChar* c1 = s1.data(); - const UChar* c2 = s2.data(); - int l = 0; - while (l < lmin && *c1 == *c2) { - c1++; - c2++; - l++; - } - if (l < lmin) - return (c1[0] > c2[0]); - - return (l1 > l2); -} - -int compare(const UString& s1, const UString& s2) -{ - const int l1 = s1.size(); - const int l2 = s2.size(); - const int lmin = l1 < l2 ? l1 : l2; - const UChar* c1 = s1.data(); - const UChar* c2 = s2.data(); - int l = 0; - while (l < lmin && *c1 == *c2) { - c1++; - c2++; - l++; - } - - if (l < lmin) - return (c1[0] > c2[0]) ? 1 : -1; - - if (l1 == l2) - return 0; - - return (l1 > l2) ? 1 : -1; -} - -bool equal(const UString::Rep* r, const UString::Rep* b) -{ - int length = r->len; - if (length != b->len) - return false; - const UChar* d = r->data(); - const UChar* s = b->data(); - for (int i = 0; i != length; ++i) { - if (d[i] != s[i]) - return false; - } - return true; -} - -CString UString::UTF8String(bool strict) const -{ - // Allocate a buffer big enough to hold all the characters. - const int length = size(); - Vector<char, 1024> buffer(length * 3); - - // Convert to runs of 8-bit characters. - char* p = buffer.data(); - const UChar* d = reinterpret_cast<const UChar*>(&data()[0]); - ConversionResult result = convertUTF16ToUTF8(&d, d + length, &p, p + buffer.size(), strict); - if (result != conversionOK) - return CString(); - - return CString(buffer.data(), p - buffer.data()); -} - -// For use in error handling code paths -- having this not be inlined helps avoid PIC branches to fetch the global on Mac OS X. -NEVER_INLINE void UString::makeNull() -{ - m_rep = &Rep::null; -} - -// For use in error handling code paths -- having this not be inlined helps avoid PIC branches to fetch the global on Mac OS X. -NEVER_INLINE UString::Rep* UString::nullRep() -{ - return &Rep::null; -} - -} // namespace JSC diff --git a/JavaScriptCore/kjs/ustring.h b/JavaScriptCore/kjs/ustring.h deleted file mode 100644 index f47b134..0000000 --- a/JavaScriptCore/kjs/ustring.h +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#ifndef _KJS_USTRING_H_ -#define _KJS_USTRING_H_ - -#include "collector.h" -#include <stdint.h> -#include <string.h> -#include <wtf/Assertions.h> -#include <wtf/FastMalloc.h> -#include <wtf/PassRefPtr.h> -#include <wtf/RefPtr.h> -#include <wtf/Vector.h> -#include <wtf/unicode/Unicode.h> - -namespace JSC { - - using WTF::PlacementNewAdoptType; - using WTF::PlacementNewAdopt; - - class IdentifierTable; - - class CString { - public: - CString() - : m_length(0) - , m_data(0) - { - } - - CString(const char*); - CString(const char*, size_t); - CString(const CString&); - - ~CString(); - - static CString adopt(char*, size_t); // buffer should be allocated with new[]. - - CString& append(const CString&); - CString& operator=(const char* c); - CString& operator=(const CString&); - CString& operator+=(const CString& c) { return append(c); } - - size_t size() const { return m_length; } - const char* c_str() const { return m_data; } - - private: - size_t m_length; - char* m_data; - }; - - typedef Vector<char, 32> CStringBuffer; - - class UString { - friend class CTI; - - public: - struct Rep { - friend class CTI; - - static PassRefPtr<Rep> create(UChar*, int); - static PassRefPtr<Rep> createCopying(const UChar*, int); - static PassRefPtr<Rep> create(PassRefPtr<Rep> base, int offset, int length); - - // Constructs a string from a UTF-8 string, using strict conversion (see comments in UTF8.h). - // Returns UString::Rep::null for null input or conversion failure. - static PassRefPtr<Rep> createFromUTF8(const char*); - - void destroy(); - - bool baseIsSelf() const { return baseString == this; } - UChar* data() const { return baseString->buf + baseString->preCapacity + offset; } - int size() const { return len; } - - unsigned hash() const { if (_hash == 0) _hash = computeHash(data(), len); return _hash; } - unsigned computedHash() const { ASSERT(_hash); return _hash; } // fast path for Identifiers - - static unsigned computeHash(const UChar*, int length); - static unsigned computeHash(const char*, int length); - static unsigned computeHash(const char* s) { return computeHash(s, strlen(s)); } - - IdentifierTable* identifierTable() const { return reinterpret_cast<IdentifierTable*>(m_identifierTable & ~static_cast<uintptr_t>(1)); } - void setIdentifierTable(IdentifierTable* table) { ASSERT(!isStatic()); m_identifierTable = reinterpret_cast<intptr_t>(table); } - - bool isStatic() const { return m_identifierTable & 1; } - void setStatic(bool v) { ASSERT(!identifierTable()); m_identifierTable = v; } - - Rep* ref() { ++rc; return this; } - ALWAYS_INLINE void deref() { if (--rc == 0) destroy(); } - - void checkConsistency() const; - - // unshared data - int offset; - int len; - int rc; // For null and empty static strings, this field does not reflect a correct count, because ref/deref are not thread-safe. A special case in destroy() guarantees that these do not get deleted. - mutable unsigned _hash; - intptr_t m_identifierTable; // A pointer to identifier table. The lowest bit is used to indicate whether the string is static (null or empty). - UString::Rep* baseString; - size_t reportedCost; - - // potentially shared data. 0 if backed up by a base string. - UChar* buf; - int usedCapacity; - int capacity; - int usedPreCapacity; - int preCapacity; - - static Rep null; - static Rep empty; - }; - - public: - UString(); - UString(const char*); - UString(const UChar*, int length); - UString(UChar*, int length, bool copy); - - UString(const UString& s) - : m_rep(s.m_rep) - { - } - - UString(const Vector<UChar>& buffer); - - ~UString() - { - } - - // Special constructor for cases where we overwrite an object in place. - UString(PlacementNewAdoptType) - : m_rep(PlacementNewAdopt) - { - } - - static UString from(int); - static UString from(unsigned int); - static UString from(long); - static UString from(double); - - struct Range { - public: - Range(int pos, int len) - : position(pos) - , length(len) - { - } - - Range() - { - } - - int position; - int length; - }; - - UString spliceSubstringsWithSeparators(const Range* substringRanges, int rangeCount, const UString* separators, int separatorCount) const; - - UString& append(const UString&); - UString& append(const char*); - UString& append(UChar); - UString& append(char c) { return append(static_cast<UChar>(static_cast<unsigned char>(c))); } - UString& append(const UChar*, int size); - - bool getCString(CStringBuffer&) const; - - // NOTE: This method should only be used for *debugging* purposes as it - // is neither Unicode safe nor free from side effects nor thread-safe. - char* ascii() const; - - /** - * Convert the string to UTF-8, assuming it is UTF-16 encoded. - * In non-strict mode, this function is tolerant of badly formed UTF-16, it - * can create UTF-8 strings that are invalid because they have characters in - * the range U+D800-U+DDFF, U+FFFE, or U+FFFF, but the UTF-8 string is - * guaranteed to be otherwise valid. - * In strict mode, error is returned as null CString. - */ - CString UTF8String(bool strict = false) const; - - UString& operator=(const char*c); - - UString& operator+=(const UString& s) { return append(s); } - UString& operator+=(const char* s) { return append(s); } - - const UChar* data() const { return m_rep->data(); } - - bool isNull() const { return (m_rep == &Rep::null); } - bool isEmpty() const { return (!m_rep->len); } - - bool is8Bit() const; - - int size() const { return m_rep->size(); } - - UChar operator[](int pos) const; - - double toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const; - double toDouble(bool tolerateTrailingJunk) const; - double toDouble() const; - - uint32_t toUInt32(bool* ok = 0) const; - uint32_t toUInt32(bool* ok, bool tolerateEmptyString) const; - uint32_t toStrictUInt32(bool* ok = 0) const; - - unsigned toArrayIndex(bool* ok = 0) const; - - int find(const UString& f, int pos = 0) const; - int find(UChar, int pos = 0) const; - int rfind(const UString& f, int pos) const; - int rfind(UChar, int pos) const; - - UString substr(int pos = 0, int len = -1) const; - - static const UString& null(); - - Rep* rep() const { return m_rep.get(); } - static Rep* nullRep(); - - UString(PassRefPtr<Rep> r) - : m_rep(r) - { - ASSERT(m_rep); - } - - size_t cost() const; - - private: - int usedCapacity() const; - int usedPreCapacity() const; - void expandCapacity(int requiredLength); - void expandPreCapacity(int requiredPreCap); - void makeNull(); - - RefPtr<Rep> m_rep; - - friend bool operator==(const UString&, const UString&); - friend PassRefPtr<Rep> concatenate(Rep*, Rep*); // returns 0 if out of memory - }; - PassRefPtr<UString::Rep> concatenate(UString::Rep*, UString::Rep*); - PassRefPtr<UString::Rep> concatenate(UString::Rep*, int); - PassRefPtr<UString::Rep> concatenate(UString::Rep*, double); - - bool operator==(const UString&, const UString&); - - inline bool operator!=(const UString& s1, const UString& s2) - { - return !JSC::operator==(s1, s2); - } - - bool operator<(const UString& s1, const UString& s2); - bool operator>(const UString& s1, const UString& s2); - - bool operator==(const UString& s1, const char* s2); - - inline bool operator!=(const UString& s1, const char* s2) - { - return !JSC::operator==(s1, s2); - } - - inline bool operator==(const char *s1, const UString& s2) - { - return operator==(s2, s1); - } - - inline bool operator!=(const char *s1, const UString& s2) - { - return !JSC::operator==(s1, s2); - } - - bool operator==(const CString&, const CString&); - - inline UString operator+(const UString& s1, const UString& s2) - { - RefPtr<UString::Rep> result = concatenate(s1.rep(), s2.rep()); - return UString(result ? result.release() : UString::nullRep()); - } - - int compare(const UString&, const UString&); - - bool equal(const UString::Rep*, const UString::Rep*); - -#ifdef NDEBUG - inline void UString::Rep::checkConsistency() const - { - } -#endif - - inline UString::UString() - : m_rep(&Rep::null) - { - } - - // Rule from ECMA 15.2 about what an array index is. - // Must exactly match string form of an unsigned integer, and be less than 2^32 - 1. - inline unsigned UString::toArrayIndex(bool* ok) const - { - unsigned i = toStrictUInt32(ok); - if (ok && i >= 0xFFFFFFFFU) - *ok = false; - return i; - } - - // We'd rather not do shared substring append for small strings, since - // this runs too much risk of a tiny initial string holding down a - // huge buffer. - // FIXME: this should be size_t but that would cause warnings until we - // fix UString sizes to be size_t instead of int - static const int minShareSize = Heap::minExtraCostSize / sizeof(UChar); - - inline size_t UString::cost() const - { - size_t capacity = (m_rep->baseString->capacity + m_rep->baseString->preCapacity) * sizeof(UChar); - size_t reportedCost = m_rep->baseString->reportedCost; - ASSERT(capacity >= reportedCost); - - size_t capacityDelta = capacity - reportedCost; - - if (capacityDelta < static_cast<size_t>(minShareSize)) - return 0; - - m_rep->baseString->reportedCost = capacity; - - return capacityDelta; - } - - struct IdentifierRepHash : PtrHash<RefPtr<JSC::UString::Rep> > { - static unsigned hash(const RefPtr<JSC::UString::Rep>& key) { return key->computedHash(); } - static unsigned hash(JSC::UString::Rep* key) { return key->computedHash(); } - }; - -} // namespace JSC - -namespace WTF { - - template<typename T> struct DefaultHash; - template<typename T> struct StrHash; - - template<> struct StrHash<JSC::UString::Rep*> { - static unsigned hash(const JSC::UString::Rep* key) { return key->hash(); } - static bool equal(const JSC::UString::Rep* a, const JSC::UString::Rep* b) { return JSC::equal(a, b); } - static const bool safeToCompareToEmptyOrDeleted = false; - }; - - template<> struct StrHash<RefPtr<JSC::UString::Rep> > : public StrHash<JSC::UString::Rep*> { - using StrHash<JSC::UString::Rep*>::hash; - static unsigned hash(const RefPtr<JSC::UString::Rep>& key) { return key->hash(); } - using StrHash<JSC::UString::Rep*>::equal; - static bool equal(const RefPtr<JSC::UString::Rep>& a, const RefPtr<JSC::UString::Rep>& b) { return JSC::equal(a.get(), b.get()); } - static bool equal(const JSC::UString::Rep* a, const RefPtr<JSC::UString::Rep>& b) { return JSC::equal(a, b.get()); } - static bool equal(const RefPtr<JSC::UString::Rep>& a, const JSC::UString::Rep* b) { return JSC::equal(a.get(), b); } - - static const bool safeToCompareToEmptyOrDeleted = false; - }; - - template<> struct DefaultHash<JSC::UString::Rep*> { - typedef StrHash<JSC::UString::Rep*> Hash; - }; - - template<> struct DefaultHash<RefPtr<JSC::UString::Rep> > { - typedef StrHash<RefPtr<JSC::UString::Rep> > Hash; - - }; - -} // namespace WTF - -#endif |