source: webkit/trunk/Source/JavaScriptCore/jsc.cpp@ 128400

Last change on this file since 128400 was 128400, checked in by [email protected], 13 years ago

JSC should have property butterflies
https://bugs.webkit.org/show_bug.cgi?id=91933

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

This changes the JSC object model. Previously, all objects had fast lookup for
named properties. Integer indexed properties were only fast if you used a
JSArray. With this change, all objects have fast indexed properties. This is
accomplished without any space overhead by using a bidirectional object layout,
aka butterflies. Each JSObject has a m_butterfly pointer where previously it
had a m_outOfLineStorage pointer. To the left of the location pointed to by
m_butterfly, we place all named out-of-line properties. To the right, we place
all indexed properties along with indexing meta-data. Though, some indexing
meta-data is placed in the 8-byte word immediately left of the pointed-to
location; this is in anticipation of the indexing meta-data being small enough
in the common case that m_butterfly always points to the first indexed
property.

This is performance neutral, except on tests that use indexed properties on
plain objects, where the speed-up is in excess of an order of magnitude.

One notable aspect of what this change brings is that it allows indexing
storage to morph over time. Currently this is only used to allow all non-array
objects to start out without any indexed storage. But it could be used for
some kinds of array type inference in the future.

  • API/JSCallbackObject.h:

(JSCallbackObject):

  • API/JSCallbackObjectFunctions.h:

(JSC::::getOwnPropertySlotByIndex):
(JSC):
(JSC::::getOwnNonIndexPropertyNames):

  • API/JSObjectRef.cpp:
  • CMakeLists.txt:
  • GNUmakefile.list.am:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Target.pri:
  • bytecode/ArrayProfile.h:

(JSC):
(JSC::arrayModeFromStructure):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::emitDirectPutById):

  • dfg/DFGAbstractState.cpp:

(JSC::DFG::AbstractState::execute):

  • dfg/DFGAdjacencyList.h:

(JSC::DFG::AdjacencyList::AdjacencyList):
(AdjacencyList):

  • dfg/DFGArrayMode.cpp:

(JSC::DFG::fromObserved):
(JSC::DFG::modeAlreadyChecked):
(JSC::DFG::modeToString):

  • dfg/DFGArrayMode.h:

(DFG):
(JSC::DFG::modeUsesButterfly):
(JSC::DFG::modeIsJSArray):
(JSC::DFG::isInBoundsAccess):
(JSC::DFG::modeSupportsLength):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::handleGetByOffset):
(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGCSEPhase.cpp:

(JSC::DFG::CSEPhase::getPropertyStorageLoadElimination):
(JSC::DFG::CSEPhase::performNodeCSE):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::addNode):
(FixupPhase):
(JSC::DFG::FixupPhase::checkArray):

  • dfg/DFGGraph.h:

(JSC::DFG::Graph::byValIsPure):

  • dfg/DFGNode.h:

(JSC::DFG::Node::Node):
(Node):

  • dfg/DFGNodeType.h:

(DFG):

  • dfg/DFGOperations.cpp:

(JSC::DFG::putByVal):

  • dfg/DFGOperations.h:
  • dfg/DFGPredictionPropagationPhase.cpp:

(JSC::DFG::PredictionPropagationPhase::propagate):

  • dfg/DFGRepatch.cpp:

(JSC::DFG::generateProtoChainAccessStub):
(JSC::DFG::tryCacheGetByID):
(JSC::DFG::tryBuildGetByIDList):
(JSC::DFG::emitPutReplaceStub):
(JSC::DFG::emitPutTransitionStub):
(JSC::DFG::tryBuildPutByIdList):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::checkArray):
(JSC::DFG::SpeculativeJIT::compileGetIndexedPropertyStorage):
(JSC::DFG::SpeculativeJIT::compileGetArrayLength):
(JSC::DFG::SpeculativeJIT::compileAllocatePropertyStorage):
(JSC::DFG::SpeculativeJIT::compileReallocatePropertyStorage):

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::callOperation):
(JSC::DFG::SpeculativeJIT::emitAllocateBasicJSObject):

  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::cachedGetById):
(JSC::DFG::SpeculativeJIT::cachedPutById):
(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::cachedGetById):
(JSC::DFG::SpeculativeJIT::cachedPutById):
(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGStructureCheckHoistingPhase.cpp:

(JSC::DFG::StructureCheckHoistingPhase::run):

  • heap/CopiedSpace.h:

(CopiedSpace):

  • jit/JIT.h:
  • jit/JITInlineMethods.h:

(JSC::JIT::emitAllocateBasicJSObject):
(JSC::JIT::emitAllocateBasicStorage):
(JSC::JIT::emitAllocateJSArray):

  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_new_array):
(JSC::JIT::emitSlow_op_new_array):

  • jit/JITPropertyAccess.cpp:

(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::compileGetDirectOffset):
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::compileGetByIdHotPath):
(JSC::JIT::emit_op_put_by_id):
(JSC::JIT::compilePutDirectOffset):
(JSC::JIT::privateCompilePatchGetArrayLength):

  • jit/JITPropertyAccess32_64.cpp:

(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::compileGetByIdHotPath):
(JSC::JIT::emit_op_put_by_id):
(JSC::JIT::compilePutDirectOffset):
(JSC::JIT::compileGetDirectOffset):
(JSC::JIT::privateCompilePatchGetArrayLength):

  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):

  • jsc.cpp:
  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::LLINT_SLOW_PATH_DECL):

  • llint/LowLevelInterpreter.asm:
  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:
  • runtime/Arguments.cpp:

(JSC::Arguments::deletePropertyByIndex):
(JSC::Arguments::defineOwnProperty):

  • runtime/ArrayConstructor.cpp:
  • runtime/ArrayConventions.h: Added.

(JSC):
(JSC::isDenseEnoughForVector):
(JSC::indexingHeaderForArray):
(JSC::baseIndexingHeaderForArray):

  • runtime/ArrayPrototype.cpp:

(JSC::ArrayPrototype::create):
(JSC):
(JSC::ArrayPrototype::ArrayPrototype):
(JSC::arrayProtoFuncToString):
(JSC::arrayProtoFuncJoin):
(JSC::arrayProtoFuncSort):
(JSC::arrayProtoFuncFilter):
(JSC::arrayProtoFuncMap):
(JSC::arrayProtoFuncEvery):
(JSC::arrayProtoFuncForEach):
(JSC::arrayProtoFuncSome):
(JSC::arrayProtoFuncReduce):
(JSC::arrayProtoFuncReduceRight):

  • runtime/ArrayPrototype.h:

(ArrayPrototype):
(JSC::ArrayPrototype::createStructure):

  • runtime/ArrayStorage.h: Added.

(JSC):
(ArrayStorage):
(JSC::ArrayStorage::ArrayStorage):
(JSC::ArrayStorage::from):
(JSC::ArrayStorage::butterfly):
(JSC::ArrayStorage::indexingHeader):
(JSC::ArrayStorage::length):
(JSC::ArrayStorage::setLength):
(JSC::ArrayStorage::vectorLength):
(JSC::ArrayStorage::setVectorLength):
(JSC::ArrayStorage::copyHeaderFromDuringGC):
(JSC::ArrayStorage::inSparseMode):
(JSC::ArrayStorage::lengthOffset):
(JSC::ArrayStorage::vectorLengthOffset):
(JSC::ArrayStorage::numValuesInVectorOffset):
(JSC::ArrayStorage::vectorOffset):
(JSC::ArrayStorage::indexBiasOffset):
(JSC::ArrayStorage::sparseMapOffset):
(JSC::ArrayStorage::sizeFor):

  • runtime/Butterfly.h: Added.

(JSC):
(Butterfly):
(JSC::Butterfly::Butterfly):
(JSC::Butterfly::totalSize):
(JSC::Butterfly::fromBase):
(JSC::Butterfly::offsetOfIndexingHeader):
(JSC::Butterfly::offsetOfPublicLength):
(JSC::Butterfly::offsetOfVectorLength):
(JSC::Butterfly::indexingHeader):
(JSC::Butterfly::propertyStorage):
(JSC::Butterfly::indexingPayload):
(JSC::Butterfly::arrayStorage):
(JSC::Butterfly::offsetOfPropertyStorage):
(JSC::Butterfly::indexOfPropertyStorage):
(JSC::Butterfly::base):

  • runtime/ButterflyInlineMethods.h: Added.

(JSC):
(JSC::Butterfly::createUninitialized):
(JSC::Butterfly::create):
(JSC::Butterfly::createUninitializedDuringCollection):
(JSC::Butterfly::base):
(JSC::Butterfly::growPropertyStorage):
(JSC::Butterfly::growArrayRight):
(JSC::Butterfly::resizeArray):
(JSC::Butterfly::unshift):
(JSC::Butterfly::shift):

  • runtime/ClassInfo.h:

(MethodTable):
(JSC):

  • runtime/IndexingHeader.h: Added.

(JSC):
(IndexingHeader):
(JSC::IndexingHeader::offsetOfIndexingHeader):
(JSC::IndexingHeader::offsetOfPublicLength):
(JSC::IndexingHeader::offsetOfVectorLength):
(JSC::IndexingHeader::IndexingHeader):
(JSC::IndexingHeader::vectorLength):
(JSC::IndexingHeader::setVectorLength):
(JSC::IndexingHeader::publicLength):
(JSC::IndexingHeader::setPublicLength):
(JSC::IndexingHeader::from):
(JSC::IndexingHeader::fromEndOf):
(JSC::IndexingHeader::propertyStorage):
(JSC::IndexingHeader::arrayStorage):
(JSC::IndexingHeader::butterfly):

  • runtime/IndexingHeaderInlineMethods.h: Added.

(JSC):
(JSC::IndexingHeader::preCapacity):
(JSC::IndexingHeader::indexingPayloadSizeInBytes):

  • runtime/IndexingType.h: Added.

(JSC):
(JSC::hasIndexingHeader):

  • runtime/JSActivation.cpp:

(JSC::JSActivation::JSActivation):
(JSC::JSActivation::visitChildren):
(JSC::JSActivation::getOwnNonIndexPropertyNames):

  • runtime/JSActivation.h:

(JSActivation):
(JSC::JSActivation::tearOff):

  • runtime/JSArray.cpp:

(JSC):
(JSC::createArrayButterflyInDictionaryIndexingMode):
(JSC::JSArray::setLengthWritable):
(JSC::JSArray::defineOwnProperty):
(JSC::JSArray::getOwnPropertySlot):
(JSC::JSArray::getOwnPropertyDescriptor):
(JSC::JSArray::put):
(JSC::JSArray::deleteProperty):
(JSC::JSArray::getOwnNonIndexPropertyNames):
(JSC::JSArray::unshiftCountSlowCase):
(JSC::JSArray::setLength):
(JSC::JSArray::pop):
(JSC::JSArray::push):
(JSC::JSArray::shiftCount):
(JSC::JSArray::unshiftCount):
(JSC::JSArray::sortNumeric):
(JSC::JSArray::sort):
(JSC::JSArray::fillArgList):
(JSC::JSArray::copyToArguments):
(JSC::JSArray::compactForSorting):

  • runtime/JSArray.h:

(JSC):
(JSArray):
(JSC::JSArray::JSArray):
(JSC::JSArray::length):
(JSC::JSArray::createStructure):
(JSC::JSArray::isLengthWritable):
(JSC::createArrayButterfly):
(JSC::JSArray::create):
(JSC::JSArray::tryCreateUninitialized):

  • runtime/JSBoundFunction.cpp:

(JSC::boundFunctionCall):
(JSC::boundFunctionConstruct):
(JSC::JSBoundFunction::finishCreation):

  • runtime/JSCell.cpp:

(JSC::JSCell::getOwnNonIndexPropertyNames):
(JSC):

  • runtime/JSCell.h:

(JSCell):

  • runtime/JSFunction.cpp:

(JSC::JSFunction::getOwnPropertySlot):
(JSC::JSFunction::getOwnPropertyDescriptor):
(JSC::JSFunction::getOwnNonIndexPropertyNames):
(JSC::JSFunction::defineOwnProperty):

  • runtime/JSFunction.h:

(JSFunction):

  • runtime/JSGlobalData.cpp:

(JSC::JSGlobalData::JSGlobalData):

  • runtime/JSGlobalData.h:

(JSGlobalData):

  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::reset):

  • runtime/JSONObject.cpp:

(JSC::Stringifier::Holder::appendNextProperty):
(JSC::Walker::walk):

  • runtime/JSObject.cpp:

(JSC):
(JSC::JSObject::visitButterfly):
(JSC::JSObject::visitChildren):
(JSC::JSFinalObject::visitChildren):
(JSC::JSObject::getOwnPropertySlotByIndex):
(JSC::JSObject::put):
(JSC::JSObject::putByIndex):
(JSC::JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists):
(JSC::JSObject::enterDictionaryIndexingMode):
(JSC::JSObject::createArrayStorage):
(JSC::JSObject::createInitialArrayStorage):
(JSC::JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode):
(JSC::JSObject::putDirectAccessor):
(JSC::JSObject::deleteProperty):
(JSC::JSObject::deletePropertyByIndex):
(JSC::JSObject::getOwnPropertyNames):
(JSC::JSObject::getOwnNonIndexPropertyNames):
(JSC::JSObject::preventExtensions):
(JSC::JSObject::fillGetterPropertySlot):
(JSC::JSObject::putIndexedDescriptor):
(JSC::JSObject::defineOwnIndexedProperty):
(JSC::JSObject::allocateSparseIndexMap):
(JSC::JSObject::deallocateSparseIndexMap):
(JSC::JSObject::putByIndexBeyondVectorLengthWithArrayStorage):
(JSC::JSObject::putByIndexBeyondVectorLength):
(JSC::JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage):
(JSC::JSObject::putDirectIndexBeyondVectorLength):
(JSC::JSObject::getNewVectorLength):
(JSC::JSObject::increaseVectorLength):
(JSC::JSObject::checkIndexingConsistency):
(JSC::JSObject::growOutOfLineStorage):
(JSC::JSObject::getOwnPropertyDescriptor):
(JSC::putDescriptor):
(JSC::JSObject::putDirectMayBeIndex):
(JSC::JSObject::defineOwnNonIndexProperty):
(JSC::JSObject::defineOwnProperty):
(JSC::JSObject::getOwnPropertySlotSlow):

  • runtime/JSObject.h:

(JSC::JSObject::getArrayLength):
(JSObject):
(JSC::JSObject::getVectorLength):
(JSC::JSObject::putDirectIndex):
(JSC::JSObject::canGetIndexQuickly):
(JSC::JSObject::getIndexQuickly):
(JSC::JSObject::canSetIndexQuickly):
(JSC::JSObject::setIndexQuickly):
(JSC::JSObject::initializeIndex):
(JSC::JSObject::completeInitialization):
(JSC::JSObject::inSparseIndexingMode):
(JSC::JSObject::butterfly):
(JSC::JSObject::outOfLineStorage):
(JSC::JSObject::offsetForLocation):
(JSC::JSObject::indexingShouldBeSparse):
(JSC::JSObject::butterflyOffset):
(JSC::JSObject::butterflyAddress):
(JSC::JSObject::arrayStorage):
(JSC::JSObject::arrayStorageOrZero):
(JSC::JSObject::ensureArrayStorage):
(JSC::JSObject::checkIndexingConsistency):
(JSC::JSNonFinalObject::JSNonFinalObject):
(JSC):
(JSC::JSObject::setButterfly):
(JSC::JSObject::setButterflyWithoutChangingStructure):
(JSC::JSObject::JSObject):
(JSC::JSObject::inlineGetOwnPropertySlot):
(JSC::JSObject::putDirectInternal):
(JSC::JSObject::setStructureAndReallocateStorageIfNecessary):
(JSC::JSObject::putDirectWithoutTransition):
(JSC::offsetInButterfly):
(JSC::offsetRelativeToPatchedStorage):
(JSC::indexRelativeToBase):
(JSC::offsetRelativeToBase):

  • runtime/JSPropertyNameIterator.cpp:

(JSC::JSPropertyNameIterator::create):

  • runtime/JSSymbolTableObject.cpp:

(JSC::JSSymbolTableObject::getOwnNonIndexPropertyNames):

  • runtime/JSSymbolTableObject.h:

(JSSymbolTableObject):

  • runtime/JSTypeInfo.h:

(JSC):
(JSC::TypeInfo::interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero):
(JSC::TypeInfo::overridesGetPropertyNames):

  • runtime/LiteralParser.cpp:

(JSC::::parse):

  • runtime/ObjectConstructor.cpp:
  • runtime/ObjectPrototype.cpp:

(JSC::ObjectPrototype::ObjectPrototype):
(JSC):

  • runtime/ObjectPrototype.h:

(ObjectPrototype):

  • runtime/PropertyOffset.h:

(JSC::offsetInOutOfLineStorage):

  • runtime/PropertyStorage.h: Added.

(JSC):

  • runtime/PutDirectIndexMode.h: Added.

(JSC):

  • runtime/RegExpMatchesArray.cpp:

(JSC::RegExpMatchesArray::RegExpMatchesArray):
(JSC):
(JSC::RegExpMatchesArray::create):
(JSC::RegExpMatchesArray::finishCreation):

  • runtime/RegExpMatchesArray.h:

(RegExpMatchesArray):
(JSC::RegExpMatchesArray::createStructure):

  • runtime/RegExpObject.cpp:

(JSC::RegExpObject::getOwnNonIndexPropertyNames):

  • runtime/RegExpObject.h:

(RegExpObject):

  • runtime/Reject.h: Added.

(JSC):
(JSC::reject):

  • runtime/SparseArrayValueMap.cpp: Added.

(JSC):

  • runtime/SparseArrayValueMap.h: Added.

(JSC):
(SparseArrayEntry):
(JSC::SparseArrayEntry::SparseArrayEntry):
(SparseArrayValueMap):
(JSC::SparseArrayValueMap::sparseMode):
(JSC::SparseArrayValueMap::setSparseMode):
(JSC::SparseArrayValueMap::lengthIsReadOnly):
(JSC::SparseArrayValueMap::setLengthIsReadOnly):
(JSC::SparseArrayValueMap::find):
(JSC::SparseArrayValueMap::remove):
(JSC::SparseArrayValueMap::notFound):
(JSC::SparseArrayValueMap::isEmpty):
(JSC::SparseArrayValueMap::contains):
(JSC::SparseArrayValueMap::size):
(JSC::SparseArrayValueMap::begin):
(JSC::SparseArrayValueMap::end):

  • runtime/SparseArrayValueMapInlineMethods.h: Added.

(JSC):
(JSC::SparseArrayValueMap::SparseArrayValueMap):
(JSC::SparseArrayValueMap::~SparseArrayValueMap):
(JSC::SparseArrayValueMap::finishCreation):
(JSC::SparseArrayValueMap::create):
(JSC::SparseArrayValueMap::destroy):
(JSC::SparseArrayValueMap::createStructure):
(JSC::SparseArrayValueMap::add):
(JSC::SparseArrayValueMap::putEntry):
(JSC::SparseArrayValueMap::putDirect):
(JSC::SparseArrayEntry::get):
(JSC::SparseArrayEntry::getNonSparseMode):
(JSC::SparseArrayValueMap::visitChildren):

  • runtime/StorageBarrier.h: Removed.
  • runtime/StringObject.cpp:

(JSC::StringObject::putByIndex):
(JSC):
(JSC::StringObject::deletePropertyByIndex):

  • runtime/StringObject.h:

(StringObject):

  • runtime/StringPrototype.cpp:
  • runtime/Structure.cpp:

(JSC::Structure::Structure):
(JSC::Structure::materializePropertyMap):
(JSC::Structure::nonPropertyTransition):
(JSC):

  • runtime/Structure.h:

(Structure):
(JSC::Structure::indexingType):
(JSC::Structure::indexingTypeIncludingHistory):
(JSC::Structure::indexingTypeOffset):
(JSC::Structure::create):

  • runtime/StructureTransitionTable.h:

(JSC):
(JSC::toAttributes):
(JSC::newIndexingType):
(JSC::StructureTransitionTable::Hash::hash):

  • tests/mozilla/js1_6/Array/regress-304828.js:

Source/WebCore:

Teach the DOM that to intercept get/put on indexed properties, you now have
to override getOwnPropertySlotByIndex and putByIndex.

No new tests because no new behavior. One test was rebased because indexed
property iteration order now matches other engines (indexed properties always
come first).

  • bindings/js/ArrayValue.cpp:

(WebCore::ArrayValue::get):

  • bindings/js/JSBlobCustom.cpp:

(WebCore::JSBlobConstructor::constructJSBlob):

  • bindings/js/JSCanvasRenderingContext2DCustom.cpp:

(WebCore::JSCanvasRenderingContext2D::setWebkitLineDash):

  • bindings/js/JSDOMStringListCustom.cpp:

(WebCore::toDOMStringList):

  • bindings/js/JSDOMStringMapCustom.cpp:

(WebCore::JSDOMStringMap::deletePropertyByIndex):
(WebCore):

  • bindings/js/JSDOMWindowCustom.cpp:

(WebCore::JSDOMWindow::getOwnPropertySlot):
(WebCore::JSDOMWindow::getOwnPropertySlotByIndex):
(WebCore):
(WebCore::JSDOMWindow::putByIndex):
(WebCore::JSDOMWindow::deletePropertyByIndex):

  • bindings/js/JSDOMWindowShell.cpp:

(WebCore::JSDOMWindowShell::getOwnPropertySlotByIndex):
(WebCore):
(WebCore::JSDOMWindowShell::putByIndex):
(WebCore::JSDOMWindowShell::deletePropertyByIndex):

  • bindings/js/JSDOMWindowShell.h:

(JSDOMWindowShell):

  • bindings/js/JSHistoryCustom.cpp:

(WebCore::JSHistory::deletePropertyByIndex):
(WebCore):

  • bindings/js/JSInspectorFrontendHostCustom.cpp:

(WebCore::populateContextMenuItems):

  • bindings/js/JSLocationCustom.cpp:

(WebCore::JSLocation::deletePropertyByIndex):
(WebCore):

  • bindings/js/JSStorageCustom.cpp:

(WebCore::JSStorage::deletePropertyByIndex):
(WebCore):

  • bindings/js/JSWebSocketCustom.cpp:

(WebCore::JSWebSocketConstructor::constructJSWebSocket):

  • bindings/js/ScriptValue.cpp:

(WebCore::jsToInspectorValue):

  • bindings/js/SerializedScriptValue.cpp:

(WebCore::CloneSerializer::serialize):

  • bindings/scripts/CodeGeneratorJS.pm:

(GenerateHeader):
(GenerateImplementation):

  • bridge/runtime_array.cpp:

(JSC::RuntimeArray::RuntimeArray):

  • bridge/runtime_array.h:

(JSC::RuntimeArray::createStructure):
(RuntimeArray):

LayoutTests:

Modify the JSON test to indicate that iterating over properties now returns
indexed properties first. This is a behavior change that makes us more
compliant with other implementations.

Also check in new expected file for the edge cases of indexed property access
with prototype accessors. This changeset introduces a known regression in that
department, which is tracked here: https://bugs.webkit.org/show_bug.cgi?id=96596

  • fast/js/resources/JSON-stringify.js:
  • platform/mac/fast/js/primitive-property-access-edge-cases-expected.txt: Added.
  • Property svn:eol-style set to native
File size: 25.5 KB
Line 
1/*
2 * Copyright (C) 1999-2000 Harri Porten ([email protected])
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2012 Apple Inc. All rights reserved.
4 * Copyright (C) 2006 Bjoern Graf ([email protected])
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23#include "config.h"
24
25#include "ButterflyInlineMethods.h"
26#include "BytecodeGenerator.h"
27#include "Completion.h"
28#include "CopiedSpaceInlineMethods.h"
29#include "ExceptionHelpers.h"
30#include "InitializeThreading.h"
31#include "Interpreter.h"
32#include "JSArray.h"
33#include "JSCTypedArrayStubs.h"
34#include "JSFunction.h"
35#include "JSLock.h"
36#include "JSString.h"
37#include "SamplingTool.h"
38#include <math.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <wtf/CurrentTime.h>
43#include <wtf/MainThread.h>
44#include <wtf/text/StringBuilder.h>
45
46#if !OS(WINDOWS)
47#include <unistd.h>
48#endif
49
50#if HAVE(READLINE)
51// readline/history.h has a Function typedef which conflicts with the WTF::Function template from WTF/Forward.h
52// We #define it to something else to avoid this conflict.
53#define Function ReadlineFunction
54#include <readline/history.h>
55#include <readline/readline.h>
56#undef Function
57#endif
58
59#if HAVE(SYS_TIME_H)
60#include <sys/time.h>
61#endif
62
63#if HAVE(SIGNAL_H)
64#include <signal.h>
65#endif
66
67#if COMPILER(MSVC) && !OS(WINCE)
68#include <crtdbg.h>
69#include <mmsystem.h>
70#include <windows.h>
71#endif
72
73#if PLATFORM(QT)
74#include <QCoreApplication>
75#include <QDateTime>
76#endif
77
78#if PLATFORM(IOS)
79#include <fenv.h>
80#include <arm/arch.h>
81#endif
82
83using namespace JSC;
84using namespace WTF;
85
86static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer);
87
88static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState*);
89static EncodedJSValue JSC_HOST_CALL functionDebug(ExecState*);
90static EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState*);
91static EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState*);
92static EncodedJSValue JSC_HOST_CALL functionGC(ExecState*);
93#ifndef NDEBUG
94static EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState*);
95static EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState*);
96#endif
97static EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*);
98static EncodedJSValue JSC_HOST_CALL functionRun(ExecState*);
99static EncodedJSValue JSC_HOST_CALL functionLoad(ExecState*);
100static EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState*);
101static EncodedJSValue JSC_HOST_CALL functionReadline(ExecState*);
102static EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*);
103static NO_RETURN_WITH_VALUE EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*);
104
105#if ENABLE(SAMPLING_FLAGS)
106static EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState*);
107static EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState*);
108#endif
109
110struct Script {
111 bool isFile;
112 char* argument;
113
114 Script(bool isFile, char *argument)
115 : isFile(isFile)
116 , argument(argument)
117 {
118 }
119};
120
121class CommandLine {
122public:
123 CommandLine(int argc, char** argv)
124 : m_interactive(false)
125 , m_dump(false)
126 , m_exitCode(false)
127 {
128 parseArguments(argc, argv);
129 }
130
131 bool m_interactive;
132 bool m_dump;
133 bool m_exitCode;
134 Vector<Script> m_scripts;
135 Vector<String> m_arguments;
136
137 void parseArguments(int, char**);
138};
139
140static const char interactivePrompt[] = "> ";
141
142class StopWatch {
143public:
144 void start();
145 void stop();
146 long getElapsedMS(); // call stop() first
147
148private:
149 double m_startTime;
150 double m_stopTime;
151};
152
153void StopWatch::start()
154{
155 m_startTime = currentTime();
156}
157
158void StopWatch::stop()
159{
160 m_stopTime = currentTime();
161}
162
163long StopWatch::getElapsedMS()
164{
165 return static_cast<long>((m_stopTime - m_startTime) * 1000);
166}
167
168class GlobalObject : public JSGlobalObject {
169private:
170 GlobalObject(JSGlobalData&, Structure*);
171
172public:
173 typedef JSGlobalObject Base;
174
175 static GlobalObject* create(JSGlobalData& globalData, Structure* structure, const Vector<String>& arguments)
176 {
177 GlobalObject* object = new (NotNull, allocateCell<GlobalObject>(globalData.heap)) GlobalObject(globalData, structure);
178 object->finishCreation(globalData, arguments);
179 return object;
180 }
181
182 static const ClassInfo s_info;
183 static const GlobalObjectMethodTable s_globalObjectMethodTable;
184
185 static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
186 {
187 return Structure::create(globalData, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), &s_info);
188 }
189
190 static bool javaScriptExperimentsEnabled(const JSGlobalObject*) { return true; }
191
192protected:
193 void finishCreation(JSGlobalData& globalData, const Vector<String>& arguments)
194 {
195 Base::finishCreation(globalData);
196
197 addFunction(globalData, "debug", functionDebug, 1);
198 addFunction(globalData, "describe", functionDescribe, 1);
199 addFunction(globalData, "print", functionPrint, 1);
200 addFunction(globalData, "quit", functionQuit, 0);
201 addFunction(globalData, "gc", functionGC, 0);
202#ifndef NDEBUG
203 addFunction(globalData, "dumpCallFrame", functionDumpCallFrame, 0);
204 addFunction(globalData, "releaseExecutableMemory", functionReleaseExecutableMemory, 0);
205#endif
206 addFunction(globalData, "version", functionVersion, 1);
207 addFunction(globalData, "run", functionRun, 1);
208 addFunction(globalData, "load", functionLoad, 1);
209 addFunction(globalData, "checkSyntax", functionCheckSyntax, 1);
210 addFunction(globalData, "jscStack", functionJSCStack, 1);
211 addFunction(globalData, "readline", functionReadline, 0);
212 addFunction(globalData, "preciseTime", functionPreciseTime, 0);
213#if ENABLE(SAMPLING_FLAGS)
214 addFunction(globalData, "setSamplingFlags", functionSetSamplingFlags, 1);
215 addFunction(globalData, "clearSamplingFlags", functionClearSamplingFlags, 1);
216#endif
217
218 addConstructableFunction(globalData, "Uint8Array", constructJSUint8Array, 1);
219 addConstructableFunction(globalData, "Uint8ClampedArray", constructJSUint8ClampedArray, 1);
220 addConstructableFunction(globalData, "Uint16Array", constructJSUint16Array, 1);
221 addConstructableFunction(globalData, "Uint32Array", constructJSUint32Array, 1);
222 addConstructableFunction(globalData, "Int8Array", constructJSInt8Array, 1);
223 addConstructableFunction(globalData, "Int16Array", constructJSInt16Array, 1);
224 addConstructableFunction(globalData, "Int32Array", constructJSInt32Array, 1);
225 addConstructableFunction(globalData, "Float32Array", constructJSFloat32Array, 1);
226 addConstructableFunction(globalData, "Float64Array", constructJSFloat64Array, 1);
227
228 JSArray* array = constructEmptyArray(globalExec());
229 for (size_t i = 0; i < arguments.size(); ++i)
230 array->putDirectIndex(globalExec(), i, jsString(globalExec(), arguments[i]));
231 putDirect(globalData, Identifier(globalExec(), "arguments"), array);
232 }
233
234 void addFunction(JSGlobalData& globalData, const char* name, NativeFunction function, unsigned arguments)
235 {
236 Identifier identifier(globalExec(), name);
237 putDirect(globalData, identifier, JSFunction::create(globalExec(), this, arguments, identifier.string(), function));
238 }
239
240 void addConstructableFunction(JSGlobalData& globalData, const char* name, NativeFunction function, unsigned arguments)
241 {
242 Identifier identifier(globalExec(), name);
243 putDirect(globalData, identifier, JSFunction::create(globalExec(), this, arguments, identifier.string(), function, NoIntrinsic, function));
244 }
245};
246COMPILE_ASSERT(!IsInteger<GlobalObject>::value, WTF_IsInteger_GlobalObject_false);
247ASSERT_CLASS_FITS_IN_CELL(GlobalObject);
248
249const ClassInfo GlobalObject::s_info = { "global", &JSGlobalObject::s_info, 0, ExecState::globalObjectTable, CREATE_METHOD_TABLE(GlobalObject) };
250const GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptExperimentsEnabled };
251
252
253GlobalObject::GlobalObject(JSGlobalData& globalData, Structure* structure)
254 : JSGlobalObject(globalData, structure, &s_globalObjectMethodTable)
255{
256}
257
258static inline SourceCode jscSource(const char* utf8, const String& filename)
259{
260 // Find the the first non-ascii character, or nul.
261 const char* pos = utf8;
262 while (*pos > 0)
263 pos++;
264 size_t asciiLength = pos - utf8;
265
266 // Fast case - string is all ascii.
267 if (!*pos)
268 return makeSource(String(utf8, asciiLength), filename);
269
270 // Slow case - contains non-ascii characters, use fromUTF8WithLatin1Fallback.
271 ASSERT(*pos < 0);
272 ASSERT(strlen(utf8) == asciiLength + strlen(pos));
273 String source = String::fromUTF8WithLatin1Fallback(utf8, asciiLength + strlen(pos));
274 return makeSource(source.impl(), filename);
275}
276
277EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
278{
279 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
280 if (i)
281 putchar(' ');
282
283 printf("%s", exec->argument(i).toString(exec)->value(exec).utf8().data());
284 }
285
286 putchar('\n');
287 fflush(stdout);
288 return JSValue::encode(jsUndefined());
289}
290
291#ifndef NDEBUG
292EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState* exec)
293{
294 if (!exec->callerFrame()->hasHostCallFrameFlag())
295 exec->globalData().interpreter->dumpCallFrame(exec->callerFrame());
296 return JSValue::encode(jsUndefined());
297}
298#endif
299
300EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec)
301{
302 fprintf(stderr, "--> %s\n", exec->argument(0).toString(exec)->value(exec).utf8().data());
303 return JSValue::encode(jsUndefined());
304}
305
306EncodedJSValue JSC_HOST_CALL functionDescribe(ExecState* exec)
307{
308 fprintf(stderr, "--> %s\n", exec->argument(0).description());
309 return JSValue::encode(jsUndefined());
310}
311
312EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState* exec)
313{
314 StringBuilder trace;
315 trace.appendLiteral("--> Stack trace:\n");
316
317 Vector<StackFrame> stackTrace;
318 Interpreter::getStackTrace(&exec->globalData(), stackTrace);
319 int i = 0;
320
321 for (Vector<StackFrame>::iterator iter = stackTrace.begin(); iter < stackTrace.end(); iter++) {
322 StackFrame level = *iter;
323 trace.append(String::format(" %i %s\n", i, level.toString(exec).utf8().data()));
324 i++;
325 }
326 fprintf(stderr, "%s", trace.toString().utf8().data());
327 return JSValue::encode(jsUndefined());
328}
329
330EncodedJSValue JSC_HOST_CALL functionGC(ExecState* exec)
331{
332 JSLockHolder lock(exec);
333 exec->heap()->collectAllGarbage();
334 return JSValue::encode(jsUndefined());
335}
336
337#ifndef NDEBUG
338EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState* exec)
339{
340 JSLockHolder lock(exec);
341 exec->globalData().releaseExecutableMemory();
342 return JSValue::encode(jsUndefined());
343}
344#endif
345
346EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*)
347{
348 // We need this function for compatibility with the Mozilla JS tests but for now
349 // we don't actually do any version-specific handling
350 return JSValue::encode(jsUndefined());
351}
352
353EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec)
354{
355 String fileName = exec->argument(0).toString(exec)->value(exec);
356 Vector<char> script;
357 if (!fillBufferWithContentsOfFile(fileName, script))
358 return JSValue::encode(throwError(exec, createError(exec, "Could not open file.")));
359
360 GlobalObject* globalObject = GlobalObject::create(exec->globalData(), GlobalObject::createStructure(exec->globalData(), jsNull()), Vector<String>());
361
362 JSValue exception;
363 StopWatch stopWatch;
364 stopWatch.start();
365 evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), &exception);
366 stopWatch.stop();
367
368 if (!!exception) {
369 throwError(globalObject->globalExec(), exception);
370 return JSValue::encode(jsUndefined());
371 }
372
373 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
374}
375
376EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec)
377{
378 String fileName = exec->argument(0).toString(exec)->value(exec);
379 Vector<char> script;
380 if (!fillBufferWithContentsOfFile(fileName, script))
381 return JSValue::encode(throwError(exec, createError(exec, "Could not open file.")));
382
383 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
384
385 JSValue evaluationException;
386 JSValue result = evaluate(globalObject->globalExec(), jscSource(script.data(), fileName), JSValue(), &evaluationException);
387 if (evaluationException)
388 throwError(exec, evaluationException);
389 return JSValue::encode(result);
390}
391
392EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec)
393{
394 String fileName = exec->argument(0).toString(exec)->value(exec);
395 Vector<char> script;
396 if (!fillBufferWithContentsOfFile(fileName, script))
397 return JSValue::encode(throwError(exec, createError(exec, "Could not open file.")));
398
399 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
400
401 StopWatch stopWatch;
402 stopWatch.start();
403
404 JSValue syntaxException;
405 bool validSyntax = checkSyntax(globalObject->globalExec(), jscSource(script.data(), fileName), &syntaxException);
406 stopWatch.stop();
407
408 if (!validSyntax)
409 throwError(exec, syntaxException);
410 return JSValue::encode(jsNumber(stopWatch.getElapsedMS()));
411}
412
413#if ENABLE(SAMPLING_FLAGS)
414EncodedJSValue JSC_HOST_CALL functionSetSamplingFlags(ExecState* exec)
415{
416 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
417 unsigned flag = static_cast<unsigned>(exec->argument(i).toNumber(exec));
418 if ((flag >= 1) && (flag <= 32))
419 SamplingFlags::setFlag(flag);
420 }
421 return JSValue::encode(jsNull());
422}
423
424EncodedJSValue JSC_HOST_CALL functionClearSamplingFlags(ExecState* exec)
425{
426 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
427 unsigned flag = static_cast<unsigned>(exec->argument(i).toNumber(exec));
428 if ((flag >= 1) && (flag <= 32))
429 SamplingFlags::clearFlag(flag);
430 }
431 return JSValue::encode(jsNull());
432}
433#endif
434
435EncodedJSValue JSC_HOST_CALL functionReadline(ExecState* exec)
436{
437 Vector<char, 256> line;
438 int c;
439 while ((c = getchar()) != EOF) {
440 // FIXME: Should we also break on \r?
441 if (c == '\n')
442 break;
443 line.append(c);
444 }
445 line.append('\0');
446 return JSValue::encode(jsString(exec, line.data()));
447}
448
449EncodedJSValue JSC_HOST_CALL functionPreciseTime(ExecState*)
450{
451 return JSValue::encode(jsNumber(currentTime()));
452}
453
454EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*)
455{
456 exit(EXIT_SUCCESS);
457
458#if COMPILER(MSVC) && OS(WINCE)
459 // Without this, Visual Studio will complain that this method does not return a value.
460 return JSValue::encode(jsUndefined());
461#endif
462}
463
464// Use SEH for Release builds only to get rid of the crash report dialog
465// (luckily the same tests fail in Release and Debug builds so far). Need to
466// be in a separate main function because the jscmain function requires object
467// unwinding.
468
469#if COMPILER(MSVC) && !COMPILER(INTEL) && !defined(_DEBUG) && !OS(WINCE)
470#define TRY __try {
471#define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
472#else
473#define TRY
474#define EXCEPT(x)
475#endif
476
477int jscmain(int argc, char** argv);
478
479int main(int argc, char** argv)
480{
481#if PLATFORM(IOS)
482 // Enabled IEEE754 denormal support.
483 fenv_t env;
484 fegetenv( &env );
485 env.__fpscr &= ~0x01000000u;
486 fesetenv( &env );
487#endif
488
489#if OS(WINDOWS)
490#if !OS(WINCE)
491 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
492 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
493 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
494 ::SetErrorMode(0);
495#endif
496
497#if defined(_DEBUG)
498 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
499 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
500 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
501 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
502 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
503 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
504#endif
505
506 timeBeginPeriod(1);
507#endif
508
509#if PLATFORM(QT)
510 QCoreApplication app(argc, argv);
511#endif
512
513 // Initialize JSC before getting JSGlobalData.
514#if ENABLE(SAMPLING_REGIONS)
515 WTF::initializeMainThread();
516#endif
517 JSC::initializeThreading();
518
519 // We can't use destructors in the following code because it uses Windows
520 // Structured Exception Handling
521 int res = 0;
522 TRY
523 res = jscmain(argc, argv);
524 EXCEPT(res = 3)
525 return res;
526}
527
528static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, bool dump)
529{
530 const char* script;
531 String fileName;
532 Vector<char> scriptBuffer;
533
534 if (dump)
535 BytecodeGenerator::setDumpsGeneratedCode(true);
536
537 JSGlobalData& globalData = globalObject->globalData();
538
539#if ENABLE(SAMPLING_FLAGS)
540 SamplingFlags::start();
541#endif
542
543 bool success = true;
544 for (size_t i = 0; i < scripts.size(); i++) {
545 if (scripts[i].isFile) {
546 fileName = scripts[i].argument;
547 if (!fillBufferWithContentsOfFile(fileName, scriptBuffer))
548 return false; // fail early so we can catch missing files
549 script = scriptBuffer.data();
550 } else {
551 script = scripts[i].argument;
552 fileName = "[Command Line]";
553 }
554
555 globalData.startSampling();
556
557 JSValue evaluationException;
558 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(script, fileName), JSValue(), &evaluationException);
559 success = success && !evaluationException;
560 if (dump && !evaluationException)
561 printf("End: %s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
562 if (evaluationException) {
563 printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
564 Identifier stackID(globalObject->globalExec(), "stack");
565 JSValue stackValue = evaluationException.get(globalObject->globalExec(), stackID);
566 if (!stackValue.isUndefinedOrNull())
567 printf("%s\n", stackValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
568 }
569
570 globalData.stopSampling();
571 globalObject->globalExec()->clearException();
572 }
573
574#if ENABLE(SAMPLING_FLAGS)
575 SamplingFlags::stop();
576#endif
577#if ENABLE(SAMPLING_REGIONS)
578 SamplingRegion::dump();
579#endif
580 globalData.dumpSampleData(globalObject->globalExec());
581#if ENABLE(SAMPLING_COUNTERS)
582 AbstractSamplingCounter::dump();
583#endif
584#if ENABLE(REGEXP_TRACING)
585 globalData.dumpRegExpTrace();
586#endif
587 return success;
588}
589
590#define RUNNING_FROM_XCODE 0
591
592static void runInteractive(GlobalObject* globalObject)
593{
594 String interpreterName("Interpreter");
595
596 while (true) {
597#if HAVE(READLINE) && !RUNNING_FROM_XCODE
598 char* line = readline(interactivePrompt);
599 if (!line)
600 break;
601 if (line[0])
602 add_history(line);
603 JSValue evaluationException;
604 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line, interpreterName), JSValue(), &evaluationException);
605 free(line);
606#else
607 printf("%s", interactivePrompt);
608 Vector<char, 256> line;
609 int c;
610 while ((c = getchar()) != EOF) {
611 // FIXME: Should we also break on \r?
612 if (c == '\n')
613 break;
614 line.append(c);
615 }
616 if (line.isEmpty())
617 break;
618 line.append('\0');
619
620 JSValue evaluationException;
621 JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line.data(), interpreterName), JSValue(), &evaluationException);
622#endif
623 if (evaluationException)
624 printf("Exception: %s\n", evaluationException.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
625 else
626 printf("%s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
627
628 globalObject->globalExec()->clearException();
629 }
630 printf("\n");
631}
632
633static NO_RETURN void printUsageStatement(bool help = false)
634{
635 fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n");
636 fprintf(stderr, " -d Dumps bytecode (debug builds only)\n");
637 fprintf(stderr, " -e Evaluate argument as script code\n");
638 fprintf(stderr, " -f Specifies a source file (deprecated)\n");
639 fprintf(stderr, " -h|--help Prints this help message\n");
640 fprintf(stderr, " -i Enables interactive mode (default if no files are specified)\n");
641#if HAVE(SIGNAL_H)
642 fprintf(stderr, " -s Installs signal handlers that exit on a crash (Unix platforms only)\n");
643#endif
644 fprintf(stderr, " -x Output exit code before terminating\n");
645 fprintf(stderr, "\n");
646 fprintf(stderr, " --options Dumps all JSC VM options and exits\n");
647 fprintf(stderr, " --dumpOptions Dumps all JSC VM options before continuing\n");
648 fprintf(stderr, " --<jsc VM option>=<value> Sets the specified JSC VM option\n");
649 fprintf(stderr, "\n");
650
651 exit(help ? EXIT_SUCCESS : EXIT_FAILURE);
652}
653
654void CommandLine::parseArguments(int argc, char** argv)
655{
656 int i = 1;
657 bool needToDumpOptions = false;
658 bool needToExit = false;
659
660 for (; i < argc; ++i) {
661 const char* arg = argv[i];
662 if (!strcmp(arg, "-f")) {
663 if (++i == argc)
664 printUsageStatement();
665 m_scripts.append(Script(true, argv[i]));
666 continue;
667 }
668 if (!strcmp(arg, "-e")) {
669 if (++i == argc)
670 printUsageStatement();
671 m_scripts.append(Script(false, argv[i]));
672 continue;
673 }
674 if (!strcmp(arg, "-i")) {
675 m_interactive = true;
676 continue;
677 }
678 if (!strcmp(arg, "-d")) {
679 m_dump = true;
680 continue;
681 }
682 if (!strcmp(arg, "-s")) {
683#if HAVE(SIGNAL_H)
684 signal(SIGILL, _exit);
685 signal(SIGFPE, _exit);
686 signal(SIGBUS, _exit);
687 signal(SIGSEGV, _exit);
688#endif
689 continue;
690 }
691 if (!strcmp(arg, "-x")) {
692 m_exitCode = true;
693 continue;
694 }
695 if (!strcmp(arg, "--")) {
696 ++i;
697 break;
698 }
699 if (!strcmp(arg, "-h") || !strcmp(arg, "--help"))
700 printUsageStatement(true);
701
702 if (!strcmp(arg, "--options")) {
703 needToDumpOptions = true;
704 needToExit = true;
705 continue;
706 }
707 if (!strcmp(arg, "--dumpOptions")) {
708 needToDumpOptions = true;
709 continue;
710 }
711
712 // See if the -- option is a JSC VM option.
713 // NOTE: At this point, we know that the arg starts with "--". Skip it.
714 if (JSC::Options::setOption(&arg[2])) {
715 // The arg was recognized as a VM option and has been parsed.
716 continue; // Just continue with the next arg.
717 }
718
719 // This arg is not recognized by the VM nor by jsc. Pass it on to the
720 // script.
721 m_scripts.append(Script(true, argv[i]));
722 }
723
724 if (m_scripts.isEmpty())
725 m_interactive = true;
726
727 for (; i < argc; ++i)
728 m_arguments.append(argv[i]);
729
730 if (needToDumpOptions)
731 JSC::Options::dumpAllOptions(stderr);
732 if (needToExit)
733 exit(EXIT_SUCCESS);
734}
735
736int jscmain(int argc, char** argv)
737{
738 // Note that the options parsing can affect JSGlobalData creation, and thus
739 // comes first.
740 CommandLine options(argc, argv);
741 RefPtr<JSGlobalData> globalData = JSGlobalData::create(ThreadStackTypeLarge, LargeHeap);
742 JSLockHolder lock(globalData.get());
743 int result;
744
745 GlobalObject* globalObject = GlobalObject::create(*globalData, GlobalObject::createStructure(*globalData, jsNull()), options.m_arguments);
746 bool success = runWithScripts(globalObject, options.m_scripts, options.m_dump);
747 if (options.m_interactive && success)
748 runInteractive(globalObject);
749
750 result = success ? 0 : 3;
751
752 if (options.m_exitCode)
753 printf("jsc exiting %d\n", result);
754
755 return result;
756}
757
758static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer)
759{
760 FILE* f = fopen(fileName.utf8().data(), "r");
761 if (!f) {
762 fprintf(stderr, "Could not open file: %s\n", fileName.utf8().data());
763 return false;
764 }
765
766 size_t bufferSize = 0;
767 size_t bufferCapacity = 1024;
768
769 buffer.resize(bufferCapacity);
770
771 while (!feof(f) && !ferror(f)) {
772 bufferSize += fread(buffer.data() + bufferSize, 1, bufferCapacity - bufferSize, f);
773 if (bufferSize == bufferCapacity) { // guarantees space for trailing '\0'
774 bufferCapacity *= 2;
775 buffer.resize(bufferCapacity);
776 }
777 }
778 fclose(f);
779 buffer[bufferSize] = '\0';
780
781 if (buffer[0] == '#' && buffer[1] == '!')
782 buffer[0] = buffer[1] = '/';
783
784 return true;
785}
Note: See TracBrowser for help on using the repository browser.