diff options
author | Leon Clarke <leonclarke@google.com> | 2010-07-15 12:03:35 +0100 |
---|---|---|
committer | Leon Clarke <leonclarke@google.com> | 2010-07-20 16:57:23 +0100 |
commit | e458d70a0d18538346f41b503114c9ebe6b2ce12 (patch) | |
tree | 86f1637deca2c524432a822e5fcedd4bef221091 /JavaScriptCore/runtime | |
parent | f43eabc081f7ce6af24b9df4953498a3cd6ca24d (diff) | |
download | external_webkit-e458d70a0d18538346f41b503114c9ebe6b2ce12.zip external_webkit-e458d70a0d18538346f41b503114c9ebe6b2ce12.tar.gz external_webkit-e458d70a0d18538346f41b503114c9ebe6b2ce12.tar.bz2 |
Merge WebKit at r63173 : Initial merge by git.
Change-Id: Ife5af0c7c6261fbbc8ae6bc08c390efa9ef10b44
Diffstat (limited to 'JavaScriptCore/runtime')
20 files changed, 265 insertions, 102 deletions
diff --git a/JavaScriptCore/runtime/Arguments.h b/JavaScriptCore/runtime/Arguments.h index 6bb180c..d892de0 100644 --- a/JavaScriptCore/runtime/Arguments.h +++ b/JavaScriptCore/runtime/Arguments.h @@ -139,7 +139,7 @@ namespace JSC { inline Arguments::Arguments(CallFrame* callFrame) : JSObject(callFrame->lexicalGlobalObject()->argumentsStructure()) - , d(new ArgumentsData) + , d(adoptPtr(new ArgumentsData)) { JSFunction* callee; ptrdiff_t firstParameterIndex; @@ -176,7 +176,7 @@ namespace JSC { inline Arguments::Arguments(CallFrame* callFrame, NoParametersType) : JSObject(callFrame->lexicalGlobalObject()->argumentsStructure()) - , d(new ArgumentsData) + , d(adoptPtr(new ArgumentsData)) { ASSERT(!asFunction(callFrame->callee())->jsExecutable()->parameterCount()); diff --git a/JavaScriptCore/runtime/ArrayPrototype.cpp b/JavaScriptCore/runtime/ArrayPrototype.cpp index 9407be7..2cb04ff 100644 --- a/JavaScriptCore/runtime/ArrayPrototype.cpp +++ b/JavaScriptCore/runtime/ArrayPrototype.cpp @@ -76,8 +76,16 @@ static inline bool isNumericCompareFunction(ExecState* exec, CallType callType, #if ENABLE(JIT) // If the JIT is enabled then we need to preserve the invariant that every // function with a CodeBlock also has JIT code. - callData.js.functionExecutable->jitCodeForCall(exec, callData.js.scopeChain); - CodeBlock* codeBlock = &callData.js.functionExecutable->generatedBytecodeForCall(); + CodeBlock* codeBlock = 0; +#if ENABLE(INTERPRETER) + if (!exec->globalData().canUseJIT()) + codeBlock = callData.js.functionExecutable->bytecodeForCall(exec, callData.js.scopeChain); + else +#endif + { + callData.js.functionExecutable->jitCodeForCall(exec, callData.js.scopeChain); + codeBlock = &callData.js.functionExecutable->generatedBytecodeForCall(); + } #else CodeBlock* codeBlock = callData.js.functionExecutable->bytecodeForCall(exec, callData.js.scopeChain); #endif diff --git a/JavaScriptCore/runtime/DatePrototype.cpp b/JavaScriptCore/runtime/DatePrototype.cpp index f8d2224..9dec33b 100644 --- a/JavaScriptCore/runtime/DatePrototype.cpp +++ b/JavaScriptCore/runtime/DatePrototype.cpp @@ -411,7 +411,7 @@ const ClassInfo DatePrototype::info = {"Date", &DateInstance::info, 0, ExecState setUTCFullYear dateProtoFuncSetUTCFullYear DontEnum|Function 3 setYear dateProtoFuncSetYear DontEnum|Function 1 getYear dateProtoFuncGetYear DontEnum|Function 0 - toJSON dateProtoFuncToJSON DontEnum|Function 0 + toJSON dateProtoFuncToJSON DontEnum|Function 1 @end */ diff --git a/JavaScriptCore/runtime/Executable.cpp b/JavaScriptCore/runtime/Executable.cpp index f33f3b4..355ee86 100644 --- a/JavaScriptCore/runtime/Executable.cpp +++ b/JavaScriptCore/runtime/Executable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -77,7 +77,7 @@ JSObject* EvalExecutable::compile(ExecState* exec, ScopeChainNode* scopeChainNod ASSERT(!m_evalCodeBlock); m_evalCodeBlock = new EvalCodeBlock(this, globalObject, source().provider(), scopeChain.localDepth()); - OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(evalNode.get(), globalObject->debugger(), scopeChain, m_evalCodeBlock->symbolTable(), m_evalCodeBlock)); + OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(evalNode.get(), globalObject->debugger(), scopeChain, m_evalCodeBlock->symbolTable(), m_evalCodeBlock))); generator->generate(); evalNode->destroyData(); @@ -112,7 +112,7 @@ JSObject* ProgramExecutable::compile(ExecState* exec, ScopeChainNode* scopeChain ASSERT(!m_programCodeBlock); m_programCodeBlock = new ProgramCodeBlock(this, GlobalCode, globalObject, source().provider()); - OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(programNode.get(), globalObject->debugger(), scopeChain, &globalObject->symbolTable(), m_programCodeBlock)); + OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(programNode.get(), globalObject->debugger(), scopeChain, &globalObject->symbolTable(), m_programCodeBlock))); generator->generate(); programNode->destroyData(); @@ -135,7 +135,7 @@ bool FunctionExecutable::compileForCall(ExecState*, ScopeChainNode* scopeChainNo ASSERT(!m_codeBlockForCall); m_codeBlockForCall = new FunctionCodeBlock(this, FunctionCode, source().provider(), source().startOffset(), false); - OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(body.get(), globalObject->debugger(), scopeChain, m_codeBlockForCall->symbolTable(), m_codeBlockForCall)); + OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(body.get(), globalObject->debugger(), scopeChain, m_codeBlockForCall->symbolTable(), m_codeBlockForCall))); generator->generate(); m_numParametersForCall = m_codeBlockForCall->m_numParameters; ASSERT(m_numParametersForCall); @@ -162,7 +162,7 @@ bool FunctionExecutable::compileForConstruct(ExecState*, ScopeChainNode* scopeCh ASSERT(!m_codeBlockForConstruct); m_codeBlockForConstruct = new FunctionCodeBlock(this, FunctionCode, source().provider(), source().startOffset(), true); - OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(body.get(), globalObject->debugger(), scopeChain, m_codeBlockForConstruct->symbolTable(), m_codeBlockForConstruct)); + OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(body.get(), globalObject->debugger(), scopeChain, m_codeBlockForConstruct->symbolTable(), m_codeBlockForConstruct))); generator->generate(); m_numParametersForConstruct = m_codeBlockForConstruct->m_numParameters; ASSERT(m_numParametersForConstruct); @@ -177,6 +177,9 @@ bool FunctionExecutable::compileForConstruct(ExecState*, ScopeChainNode* scopeCh void EvalExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChainNode) { +#if ENABLE(INTERPRETER) + ASSERT(exec->globalData().canUseJIT()); +#endif CodeBlock* codeBlock = &bytecode(exec, scopeChainNode); m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, codeBlock); @@ -188,6 +191,9 @@ void EvalExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChain void ProgramExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChainNode) { +#if ENABLE(INTERPRETER) + ASSERT(exec->globalData().canUseJIT()); +#endif CodeBlock* codeBlock = &bytecode(exec, scopeChainNode); m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, codeBlock); @@ -199,6 +205,9 @@ void ProgramExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeCh void FunctionExecutable::generateJITCodeForCall(ExecState* exec, ScopeChainNode* scopeChainNode) { +#if ENABLE(INTERPRETER) + ASSERT(exec->globalData().canUseJIT()); +#endif CodeBlock* codeBlock = bytecodeForCall(exec, scopeChainNode); m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, codeBlock, &m_jitCodeForCallWithArityCheck); @@ -210,6 +219,9 @@ void FunctionExecutable::generateJITCodeForCall(ExecState* exec, ScopeChainNode* void FunctionExecutable::generateJITCodeForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode) { +#if ENABLE(INTERPRETER) + ASSERT(exec->globalData().canUseJIT()); +#endif CodeBlock* codeBlock = bytecodeForConstruct(exec, scopeChainNode); m_jitCodeForConstruct = JIT::compile(scopeChainNode->globalData, codeBlock, &m_jitCodeForConstructWithArityCheck); @@ -229,11 +241,11 @@ void FunctionExecutable::markAggregate(MarkStack& markStack) m_codeBlockForConstruct->markAggregate(markStack); } -ExceptionInfo* FunctionExecutable::reparseExceptionInfo(JSGlobalData* globalData, ScopeChainNode* scopeChainNode, CodeBlock* codeBlock) +PassOwnPtr<ExceptionInfo> FunctionExecutable::reparseExceptionInfo(JSGlobalData* globalData, ScopeChainNode* scopeChainNode, CodeBlock* codeBlock) { RefPtr<FunctionBodyNode> newFunctionBody = globalData->parser->parse<FunctionBodyNode>(globalData, 0, 0, m_source); if (!newFunctionBody) - return 0; + return PassOwnPtr<ExceptionInfo>(); if (m_forceUsesArguments) newFunctionBody->setUsesArguments(); newFunctionBody->finishParsing(m_parameters, m_name); @@ -241,18 +253,23 @@ ExceptionInfo* FunctionExecutable::reparseExceptionInfo(JSGlobalData* globalData ScopeChain scopeChain(scopeChainNode); JSGlobalObject* globalObject = scopeChain.globalObject(); - OwnPtr<CodeBlock> newCodeBlock(new FunctionCodeBlock(this, FunctionCode, source().provider(), source().startOffset(), codeBlock->m_isConstructor)); + OwnPtr<CodeBlock> newCodeBlock(adoptPtr(new FunctionCodeBlock(this, FunctionCode, source().provider(), source().startOffset(), codeBlock->m_isConstructor))); globalData->functionCodeBlockBeingReparsed = newCodeBlock.get(); - OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(newFunctionBody.get(), globalObject->debugger(), scopeChain, newCodeBlock->symbolTable(), newCodeBlock.get())); + OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(newFunctionBody.get(), globalObject->debugger(), scopeChain, newCodeBlock->symbolTable(), newCodeBlock.get()))); generator->setRegeneratingForExceptionInfo(static_cast<FunctionCodeBlock*>(codeBlock)); generator->generate(); ASSERT(newCodeBlock->instructionCount() == codeBlock->instructionCount()); #if ENABLE(JIT) - JITCode newJITCode = JIT::compile(globalData, newCodeBlock.get()); - ASSERT(codeBlock->m_isConstructor ? newJITCode.size() == generatedJITCodeForConstruct().size() : newJITCode.size() == generatedJITCodeForCall().size()); +#if ENABLE(INTERPRETER) + if (globalData->canUseJIT()) +#endif + { + JITCode newJITCode = JIT::compile(globalData, newCodeBlock.get()); + ASSERT(codeBlock->m_isConstructor ? newJITCode.size() == generatedJITCodeForConstruct().size() : newJITCode.size() == generatedJITCodeForCall().size()); + } #endif globalData->functionCodeBlockBeingReparsed = 0; @@ -260,26 +277,31 @@ ExceptionInfo* FunctionExecutable::reparseExceptionInfo(JSGlobalData* globalData return newCodeBlock->extractExceptionInfo(); } -ExceptionInfo* EvalExecutable::reparseExceptionInfo(JSGlobalData* globalData, ScopeChainNode* scopeChainNode, CodeBlock* codeBlock) +PassOwnPtr<ExceptionInfo> EvalExecutable::reparseExceptionInfo(JSGlobalData* globalData, ScopeChainNode* scopeChainNode, CodeBlock* codeBlock) { RefPtr<EvalNode> newEvalBody = globalData->parser->parse<EvalNode>(globalData, 0, 0, m_source); if (!newEvalBody) - return 0; + return PassOwnPtr<ExceptionInfo>(); ScopeChain scopeChain(scopeChainNode); JSGlobalObject* globalObject = scopeChain.globalObject(); - OwnPtr<EvalCodeBlock> newCodeBlock(new EvalCodeBlock(this, globalObject, source().provider(), scopeChain.localDepth())); + OwnPtr<EvalCodeBlock> newCodeBlock(adoptPtr(new EvalCodeBlock(this, globalObject, source().provider(), scopeChain.localDepth()))); - OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(newEvalBody.get(), globalObject->debugger(), scopeChain, newCodeBlock->symbolTable(), newCodeBlock.get())); + OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(newEvalBody.get(), globalObject->debugger(), scopeChain, newCodeBlock->symbolTable(), newCodeBlock.get()))); generator->setRegeneratingForExceptionInfo(static_cast<EvalCodeBlock*>(codeBlock)); generator->generate(); ASSERT(newCodeBlock->instructionCount() == codeBlock->instructionCount()); #if ENABLE(JIT) - JITCode newJITCode = JIT::compile(globalData, newCodeBlock.get()); - ASSERT(newJITCode.size() == generatedJITCodeForCall().size()); +#if ENABLE(INTERPRETER) + if (globalData->canUseJIT()) +#endif + { + JITCode newJITCode = JIT::compile(globalData, newCodeBlock.get()); + ASSERT(newJITCode.size() == generatedJITCodeForCall().size()); + } #endif return newCodeBlock->extractExceptionInfo(); @@ -334,6 +356,10 @@ UString FunctionExecutable::paramString() const return builder.build(); } -}; - +PassOwnPtr<ExceptionInfo> ProgramExecutable::reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) +{ + // CodeBlocks for program code are transient and therefore do not gain from from throwing out their exception information. + return PassOwnPtr<ExceptionInfo>(); +} +} diff --git a/JavaScriptCore/runtime/Executable.h b/JavaScriptCore/runtime/Executable.h index 3320fe1..516d6ce 100644 --- a/JavaScriptCore/runtime/Executable.h +++ b/JavaScriptCore/runtime/Executable.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,6 +31,7 @@ #include "Interpreter.h" #include "Nodes.h" #include "SamplingTool.h" +#include <wtf/PassOwnPtr.h> namespace JSC { @@ -171,7 +172,7 @@ namespace JSC { bool usesArguments() const { return m_features & ArgumentsFeature; } bool needsActivation() const { return m_features & (EvalFeature | ClosureFeature | WithFeature | CatchFeature); } - virtual ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) = 0; + virtual PassOwnPtr<ExceptionInfo> reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) = 0; protected: void recordParse(CodeFeatures features, int firstLine, int lastLine) @@ -203,7 +204,6 @@ namespace JSC { JSObject* compile(ExecState*, ScopeChainNode*); - ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*); static PassRefPtr<EvalExecutable> create(ExecState* exec, const SourceCode& source) { return adoptRef(new EvalExecutable(exec, source)); } private: @@ -212,6 +212,9 @@ namespace JSC { , m_evalCodeBlock(0) { } + + virtual PassOwnPtr<ExceptionInfo> reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*); + EvalCodeBlock* m_evalCodeBlock; #if ENABLE(JIT) @@ -249,15 +252,15 @@ namespace JSC { JSObject* checkSyntax(ExecState*); JSObject* compile(ExecState*, ScopeChainNode*); - // CodeBlocks for program code are transient and therefore do not gain from from throwing out there exception information. - ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) { ASSERT_NOT_REACHED(); return 0; } - private: ProgramExecutable(ExecState* exec, const SourceCode& source) : ScriptExecutable(exec, source) , m_programCodeBlock(0) { } + + virtual PassOwnPtr<ExceptionInfo> reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*); + ProgramCodeBlock* m_programCodeBlock; #if ENABLE(JIT) @@ -350,7 +353,6 @@ namespace JSC { SharedSymbolTable* symbolTable() const { return m_symbolTable; } void recompile(ExecState*); - ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*); void markAggregate(MarkStack& markStack); static PassRefPtr<FunctionExecutable> fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, int* errLine = 0, UString* errMsg = 0); @@ -386,6 +388,8 @@ namespace JSC { bool compileForCall(ExecState*, ScopeChainNode*); bool compileForConstruct(ExecState*, ScopeChainNode*); + virtual PassOwnPtr<ExceptionInfo> reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*); + unsigned m_numVariables : 31; bool m_forceUsesArguments : 1; diff --git a/JavaScriptCore/runtime/JSArray.cpp b/JavaScriptCore/runtime/JSArray.cpp index 78667cd..362f89b 100644 --- a/JavaScriptCore/runtime/JSArray.cpp +++ b/JavaScriptCore/runtime/JSArray.cpp @@ -847,7 +847,7 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, tree.abstractor().m_nodes.resize(usedVectorLength + (m_storage->m_sparseValueMap ? m_storage->m_sparseValueMap->size() : 0)); if (callType == CallTypeJS) - tree.abstractor().m_cachedCall.set(new CachedCall(exec, asFunction(compareFunction), 2, exec->exceptionSlot())); + tree.abstractor().m_cachedCall = adoptPtr(new CachedCall(exec, asFunction(compareFunction), 2, exec->exceptionSlot())); if (!tree.abstractor().m_nodes.begin()) { throwOutOfMemoryError(exec); diff --git a/JavaScriptCore/runtime/JSFunction.cpp b/JavaScriptCore/runtime/JSFunction.cpp index 7fcd037..49cc8fa 100644 --- a/JavaScriptCore/runtime/JSFunction.cpp +++ b/JavaScriptCore/runtime/JSFunction.cpp @@ -42,13 +42,14 @@ using namespace WTF; using namespace Unicode; namespace JSC { - +#if ENABLE(JIT) EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState* exec) { CodeBlock* codeBlock = exec->callerFrame()->codeBlock(); unsigned vPCIndex = codeBlock->bytecodeOffset(exec, exec->returnPC()); return throwVMError(exec, createNotAConstructorError(exec, exec->callee(), vPCIndex, codeBlock)); } +#endif ASSERT_CLASS_FITS_IN_CELL(JSFunction); diff --git a/JavaScriptCore/runtime/JSGlobalData.cpp b/JavaScriptCore/runtime/JSGlobalData.cpp index 30a5ef9..1508750 100644 --- a/JavaScriptCore/runtime/JSGlobalData.cpp +++ b/JavaScriptCore/runtime/JSGlobalData.cpp @@ -58,6 +58,7 @@ #if PLATFORM(MAC) #include "ProfilerServer.h" +#include <CoreFoundation/CoreFoundation.h> #endif using namespace WTF; @@ -156,6 +157,19 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread #if PLATFORM(MAC) startProfilerServerIfNeeded(); #endif +#if ENABLE(JIT) && ENABLE(INTERPRETER) +#if PLATFORM(MAC) + CFStringRef canUseJITKey = CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman); + CFBooleanRef canUseJIT = (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication); + m_canUseJIT = kCFBooleanTrue == canUseJIT; + CFRelease(canUseJIT); + CFRelease(canUseJITKey); +#elif OS(UNIX) + m_canUseJIT = !getenv("JSC_FORCE_INTERPRETER"); +#else + m_canUseJIT = true; +#endif +#endif } JSGlobalData::~JSGlobalData() @@ -228,7 +242,7 @@ JSGlobalData& JSGlobalData::sharedInstance() { JSGlobalData*& instance = sharedInstanceInternal(); if (!instance) { - instance = new JSGlobalData(APIShared, ThreadStackTypeSmall); + instance = adoptRef(new JSGlobalData(APIShared, ThreadStackTypeSmall)).leakRef(); #if ENABLE(JSC_MULTIPLE_THREADS) instance->makeUsableFromMultipleThreads(); #endif diff --git a/JavaScriptCore/runtime/JSGlobalData.h b/JavaScriptCore/runtime/JSGlobalData.h index f99c8d6..f3f6cba 100644 --- a/JavaScriptCore/runtime/JSGlobalData.h +++ b/JavaScriptCore/runtime/JSGlobalData.h @@ -167,6 +167,13 @@ namespace JSC { ExecutableAllocator executableAllocator; #endif +#if ENABLE(JIT) +#if ENABLE(INTERPRETER) + bool canUseJIT() { return m_canUseJIT; } +#endif +#else + bool canUseJIT() { return false; } +#endif Lexer* lexer; Parser* parser; Interpreter* interpreter; @@ -233,6 +240,9 @@ namespace JSC { JSGlobalData(GlobalDataType, ThreadStackType); static JSGlobalData*& sharedInstanceInternal(); void createNativeThunk(); +#if ENABLE(JIT) && ENABLE(INTERPRETER) + bool m_canUseJIT; +#endif }; } // namespace JSC diff --git a/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp b/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp index f625323..d88d6a9 100644 --- a/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp +++ b/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp @@ -141,6 +141,7 @@ static JSValue decode(ExecState* exec, const char* doNotUnescape, bool strict) bool isStrWhiteSpace(UChar c) { switch (c) { + // ECMA-262-5th 7.2 & 7.3 case 0x0009: case 0x000A: case 0x000B: @@ -150,6 +151,7 @@ bool isStrWhiteSpace(UChar c) case 0x00A0: case 0x2028: case 0x2029: + case 0xFEFF: return true; default: return c > 0xff && isSeparatorSpace(c); @@ -194,6 +196,28 @@ double parseIntOverflow(const char* s, int length, int radix) return number; } +double parseIntOverflow(const UChar* s, int length, int radix) +{ + double number = 0.0; + double radixMultiplier = 1.0; + + for (const UChar* p = s + length - 1; p >= s; p--) { + if (radixMultiplier == Inf) { + if (*p != '0') { + number = Inf; + break; + } + } else { + int digit = parseDigit(*p, radix); + number += digit * radixMultiplier; + } + + radixMultiplier *= radix; + } + + return number; +} + static double parseInt(const UString& s, int radix) { int length = s.size(); diff --git a/JavaScriptCore/runtime/JSGlobalObjectFunctions.h b/JavaScriptCore/runtime/JSGlobalObjectFunctions.h index 91dfca8..e634fae 100644 --- a/JavaScriptCore/runtime/JSGlobalObjectFunctions.h +++ b/JavaScriptCore/runtime/JSGlobalObjectFunctions.h @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) * Copyright (C) 2007 Maks Orlovich * @@ -53,6 +53,7 @@ namespace JSC { static const double mantissaOverflowLowerBound = 9007199254740992.0; double parseIntOverflow(const char*, int length, int radix); + double parseIntOverflow(const UChar*, int length, int radix); bool isStrWhiteSpace(UChar); } // namespace JSC diff --git a/JavaScriptCore/runtime/JSObject.h b/JavaScriptCore/runtime/JSObject.h index edd376c..4201703 100644 --- a/JavaScriptCore/runtime/JSObject.h +++ b/JavaScriptCore/runtime/JSObject.h @@ -177,6 +177,7 @@ namespace JSC { void putDirect(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot); void putDirect(const Identifier& propertyName, JSValue value, unsigned attr = 0); + void putDirect(const Identifier& propertyName, JSValue value, PutPropertySlot&); void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr = 0); void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot); @@ -590,6 +591,11 @@ inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, u putDirectInternal(propertyName, value, attributes, false, slot, 0); } +inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, PutPropertySlot& slot) +{ + putDirectInternal(propertyName, value, 0, false, slot, 0); +} + inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot) { putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, value); @@ -692,6 +698,12 @@ inline void JSValue::put(ExecState* exec, const Identifier& propertyName, JSValu asCell()->put(exec, propertyName, value, slot); } +inline void JSValue::putDirect(ExecState*, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) +{ + ASSERT(isCell() && isObject()); + asObject(asCell())->putDirect(propertyName, value, slot); +} + inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue value) { if (UNLIKELY(!isCell())) { diff --git a/JavaScriptCore/runtime/JSValue.h b/JavaScriptCore/runtime/JSValue.h index 9190f70..3c6bc09 100644 --- a/JavaScriptCore/runtime/JSValue.h +++ b/JavaScriptCore/runtime/JSValue.h @@ -181,6 +181,7 @@ namespace JSC { JSValue get(ExecState*, unsigned propertyName) const; JSValue get(ExecState*, unsigned propertyName, PropertySlot&) const; void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); + void putDirect(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); void put(ExecState*, unsigned propertyName, JSValue); bool needsThisConversion() const; diff --git a/JavaScriptCore/runtime/RegExpConstructor.cpp b/JavaScriptCore/runtime/RegExpConstructor.cpp index 166a021..fa2a1e2 100644 --- a/JavaScriptCore/runtime/RegExpConstructor.cpp +++ b/JavaScriptCore/runtime/RegExpConstructor.cpp @@ -35,6 +35,7 @@ #include "RegExpPrototype.h" #include "RegExp.h" #include "RegExpCache.h" +#include <wtf/PassOwnPtr.h> namespace JSC { @@ -95,7 +96,7 @@ const ClassInfo RegExpConstructor::info = { "Function", &InternalFunction::info, RegExpConstructor::RegExpConstructor(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, RegExpPrototype* regExpPrototype) : InternalFunction(&exec->globalData(), globalObject, structure, Identifier(exec, "RegExp")) - , d(new RegExpConstructorPrivate) + , d(adoptPtr(new RegExpConstructorPrivate)) { // ECMA 15.10.5.1 RegExp.prototype putDirectWithoutTransition(exec->propertyNames().prototype, regExpPrototype, DontEnum | DontDelete | ReadOnly); diff --git a/JavaScriptCore/runtime/RegExpObject.cpp b/JavaScriptCore/runtime/RegExpObject.cpp index 4824944..0f2c1e1 100644 --- a/JavaScriptCore/runtime/RegExpObject.cpp +++ b/JavaScriptCore/runtime/RegExpObject.cpp @@ -29,6 +29,7 @@ #include "Lookup.h" #include "RegExpConstructor.h" #include "RegExpPrototype.h" +#include <wtf/PassOwnPtr.h> namespace JSC { @@ -61,7 +62,7 @@ const ClassInfo RegExpObject::info = { "RegExp", 0, 0, ExecState::regExpTable }; RegExpObject::RegExpObject(JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, NonNullPassRefPtr<RegExp> regExp) : JSObjectWithGlobalObject(globalObject, structure) - , d(new RegExpObjectData(regExp, 0)) + , d(adoptPtr(new RegExpObjectData(regExp, 0))) { } diff --git a/JavaScriptCore/runtime/RegExpPrototype.cpp b/JavaScriptCore/runtime/RegExpPrototype.cpp index 834412b..ac215ec 100644 --- a/JavaScriptCore/runtime/RegExpPrototype.cpp +++ b/JavaScriptCore/runtime/RegExpPrototype.cpp @@ -46,10 +46,8 @@ static EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState*); // ECMA 15.10.5 -const ClassInfo RegExpPrototype::info = { "RegExpPrototype", 0, 0, 0 }; - RegExpPrototype::RegExpPrototype(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, Structure* prototypeFunctionStructure) - : JSObject(structure) + : RegExpObject(globalObject, structure, RegExp::create(&exec->globalData(), "", "")) { putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 0, exec->propertyNames().compile, regExpProtoFuncCompile), DontEnum); putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, globalObject, prototypeFunctionStructure, 0, exec->propertyNames().exec, regExpProtoFuncExec), DontEnum); diff --git a/JavaScriptCore/runtime/RegExpPrototype.h b/JavaScriptCore/runtime/RegExpPrototype.h index 77c1ea7..eb4ae00 100644 --- a/JavaScriptCore/runtime/RegExpPrototype.h +++ b/JavaScriptCore/runtime/RegExpPrototype.h @@ -21,16 +21,14 @@ #ifndef RegExpPrototype_h #define RegExpPrototype_h +#include "RegExpObject.h" #include "JSObject.h" namespace JSC { - class RegExpPrototype : public JSObject { + class RegExpPrototype : public RegExpObject { public: RegExpPrototype(ExecState*, JSGlobalObject*, NonNullPassRefPtr<Structure>, Structure* prototypeFunctionStructure); - - virtual const ClassInfo* classInfo() const { return &info; } - static const ClassInfo info; }; } // namespace JSC diff --git a/JavaScriptCore/runtime/SmallStrings.cpp b/JavaScriptCore/runtime/SmallStrings.cpp index 0f5df4a..822303c 100644 --- a/JavaScriptCore/runtime/SmallStrings.cpp +++ b/JavaScriptCore/runtime/SmallStrings.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 2010 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,10 +28,11 @@ #include "JSGlobalObject.h" #include "JSString.h" - #include <wtf/Noncopyable.h> +#include <wtf/PassOwnPtr.h> namespace JSC { + static const unsigned numCharactersToStore = 0x100; static inline bool isMarked(JSString* string) @@ -126,7 +127,7 @@ void SmallStrings::createEmptyString(JSGlobalData* globalData) void SmallStrings::createSingleCharacterString(JSGlobalData* globalData, unsigned char character) { if (!m_storage) - m_storage.set(new SmallStringsStorage); + m_storage = adoptPtr(new SmallStringsStorage); ASSERT(!m_singleCharacterStrings[character]); m_singleCharacterStrings[character] = new (globalData) JSString(globalData, m_storage->rep(character), JSString::HasOtherOwner); } @@ -134,7 +135,7 @@ void SmallStrings::createSingleCharacterString(JSGlobalData* globalData, unsigne UString::Rep* SmallStrings::singleCharacterStringRep(unsigned char character) { if (!m_storage) - m_storage.set(new SmallStringsStorage); + m_storage = adoptPtr(new SmallStringsStorage); return m_storage->rep(character); } diff --git a/JavaScriptCore/runtime/StringPrototype.cpp b/JavaScriptCore/runtime/StringPrototype.cpp index 8b56d53..fb6e0f3 100644 --- a/JavaScriptCore/runtime/StringPrototype.cpp +++ b/JavaScriptCore/runtime/StringPrototype.cpp @@ -466,6 +466,8 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); + if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible + return throwVMTypeError(exec); UString s = thisValue.toThisString(exec); unsigned len = s.size(); JSValue a0 = exec->argument(0); @@ -484,6 +486,8 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); + if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible + return throwVMTypeError(exec); UString s = thisValue.toThisString(exec); unsigned len = s.size(); JSValue a0 = exec->argument(0); @@ -508,13 +512,16 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState* exec) ? jsString(exec, asString(thisValue), asString(v)) : jsString(exec, asString(thisValue), v.toString(exec))); } - + if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible + return throwVMTypeError(exec); return JSValue::encode(jsString(exec, thisValue)); } EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); + if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible + return throwVMTypeError(exec); UString s = thisValue.toThisString(exec); int len = s.size(); @@ -544,6 +551,8 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); + if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible + return throwVMTypeError(exec); UString s = thisValue.toThisString(exec); int len = s.size(); @@ -571,6 +580,8 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); + if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible + return throwVMTypeError(exec); UString s = thisValue.toThisString(exec); JSValue a0 = exec->argument(0); @@ -623,6 +634,8 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); + if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible + return throwVMTypeError(exec); UString s = thisValue.toThisString(exec); JSValue a0 = exec->argument(0); @@ -649,6 +662,8 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); + if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible + return throwVMTypeError(exec); UString s = thisValue.toThisString(exec); int len = s.size(); @@ -674,6 +689,8 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); + if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible + return throwVMTypeError(exec); UString s = thisValue.toThisString(exec); JSValue a0 = exec->argument(0); @@ -738,6 +755,8 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); + if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible + return throwVMTypeError(exec); UString s = thisValue.toThisString(exec); int len = s.size(); @@ -761,6 +780,8 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); + if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible + return throwVMTypeError(exec); UString s = thisValue.toThisString(exec); int len = s.size(); @@ -793,6 +814,8 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); + if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible + return throwVMTypeError(exec); JSString* sVal = thisValue.toThisJSString(exec); const UString& s = sVal->value(exec); @@ -831,6 +854,8 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); + if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible + return throwVMTypeError(exec); JSString* sVal = thisValue.toThisJSString(exec); const UString& s = sVal->value(exec); @@ -868,10 +893,13 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState* exec) EncodedJSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState* exec) { - JSValue thisValue = exec->hostThisValue(); if (exec->argumentCount() < 1) return JSValue::encode(jsNumber(exec, 0)); + JSValue thisValue = exec->hostThisValue(); + if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible + return throwVMTypeError(exec); + UString s = thisValue.toThisString(exec); JSValue a0 = exec->argument(0); return JSValue::encode(jsNumber(exec, localeCompare(s, a0.toString(exec)))); @@ -1045,6 +1073,8 @@ static inline bool isTrimWhitespace(UChar c) static inline JSValue trimString(ExecState* exec, JSValue thisValue, int trimKind) { + if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible + return throwTypeError(exec); UString str = thisValue.toThisString(exec); unsigned left = 0; if (trimKind & TrimLeft) { diff --git a/JavaScriptCore/runtime/UString.cpp b/JavaScriptCore/runtime/UString.cpp index 5a6a644..c442500 100644 --- a/JavaScriptCore/runtime/UString.cpp +++ b/JavaScriptCore/runtime/UString.cpp @@ -242,13 +242,33 @@ UChar UString::operator[](unsigned pos) const return data()[pos]; } +static inline bool isInfinity(double number) +{ + return number == Inf || number == -Inf; +} + +static bool isInfinity(const UChar* data, const UChar* end) +{ + return data + 7 < end + && data[0] == 'I' + && data[1] == 'n' + && data[2] == 'f' + && data[3] == 'i' + && data[4] == 'n' + && data[5] == 'i' + && data[6] == 't' + && data[7] == 'y'; +} + double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const { - if (size() == 1) { + unsigned size = this->size(); + + if (size == 1) { UChar c = data()[0]; if (isASCIIDigit(c)) return c - '0'; - if (isASCIISpace(c) && tolerateEmptyString) + if (isStrWhiteSpace(c) && tolerateEmptyString) return 0; return NaN; } @@ -264,77 +284,90 @@ double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) co // need to skip all StrWhiteSpace. The isStrWhiteSpace function does the // right thing but requires UChar, not char, for its argument. - CString s = UTF8String(); - if (s.isNull()) - return NaN; - const char* c = s.data(); + const UChar* data = this->data(); + const UChar* end = data + size; - // skip leading white space - while (isASCIISpace(*c)) - c++; + // Skip leading white space. + for (; data < end; ++data) { + if (!isStrWhiteSpace(*data)) + break; + } - // empty string ? - if (*c == '\0') + // Empty string. + if (data == end) 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 + double number; + + if (data[0] == '0' && data + 2 < end && (data[1] | 0x20) == 'x' && isASCIIHexDigit(data[2])) { + // Hex number. + data += 2; + const UChar* firstDigitPosition = data; + number = 0; + while (true) { + number = number * 16 + toASCIIHexValue(*data); + ++data; + if (data == end) + break; + if (!isASCIIHexDigit(*data)) break; } - - if (d >= mantissaOverflowLowerBound) - d = parseIntOverflow(firstDigitPosition, c - firstDigitPosition, 16); + if (number >= mantissaOverflowLowerBound) + number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 16); } else { - // regular number ? - char* end; - d = WTF::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++; - } + // Decimal number. + + // Put into a null-terminated byte buffer. + Vector<char, 32> byteBuffer; + for (const UChar* characters = data; characters < end; ++characters) { + UChar character = *characters; + byteBuffer.append(isASCII(character) ? character : 0); + } + byteBuffer.append(0); + char* byteBufferEnd; + number = WTF::strtod(byteBuffer.data(), &byteBufferEnd); + const UChar* pastNumber = data + (byteBufferEnd - byteBuffer.data()); + + if ((number || pastNumber != data) && !isInfinity(number)) + data = pastNumber; + else { // 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; + double signedInfinity = Inf; + if (data < end) { + if (*data == '+') + data++; + else if (*data == '-') { + signedInfinity = -Inf; + data++; + } + } + if (isInfinity(data, end)) { + number = signedInfinity; + data += 8; + } else if (isInfinity(number) && data < end && (*data | 0x20) != 'i') + data = pastNumber; else return NaN; } } + // Look for trailing junk. if (!tolerateTrailingJunk) { - // allow trailing white space - while (isASCIISpace(*c)) - c++; - if (c != s.data() + s.length()) - d = NaN; + // Allow trailing white space. + for (; data < end; ++data) { + if (!isStrWhiteSpace(*data)) + break; + } + if (data != end) + return NaN; } - return d; + return number; } double UString::toDouble(bool tolerateTrailingJunk) const |