From d441d6f39bb846989d95bcf5caf387b42414718d Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Fri, 13 Sep 2013 12:51:20 +0200 Subject: Import Qt5x2 branch of QtWebkit for Qt 5.2 Importing a new snapshot of webkit. Change-Id: I2d01ad12cdc8af8cb015387641120a9d7ea5f10c Reviewed-by: Allan Sandfeld Jensen --- .../bytecompiler/BytecodeGenerator.cpp | 534 +++++++------ .../bytecompiler/BytecodeGenerator.h | 234 +++--- Source/JavaScriptCore/bytecompiler/Label.h | 2 + Source/JavaScriptCore/bytecompiler/LabelScope.h | 67 +- .../JavaScriptCore/bytecompiler/NodesCodegen.cpp | 835 ++++++++++++--------- .../bytecompiler/StaticPropertyAnalysis.h | 67 ++ .../bytecompiler/StaticPropertyAnalyzer.h | 170 +++++ 7 files changed, 1154 insertions(+), 755 deletions(-) create mode 100644 Source/JavaScriptCore/bytecompiler/StaticPropertyAnalysis.h create mode 100644 Source/JavaScriptCore/bytecompiler/StaticPropertyAnalyzer.h (limited to 'Source/JavaScriptCore/bytecompiler') diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp index 507241696..b4e3d3de8 100644 --- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009, 2012, 2013 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich * Copyright (C) 2012 Igalia, S.L. * @@ -32,95 +32,21 @@ #include "BytecodeGenerator.h" #include "BatchedTransitionOptimizer.h" -#include "Comment.h" #include "Interpreter.h" #include "JSActivation.h" #include "JSFunction.h" #include "JSNameScope.h" #include "LowLevelInterpreter.h" +#include "Operations.h" #include "Options.h" #include "StrongInlines.h" +#include "UnlinkedCodeBlock.h" #include using namespace std; namespace JSC { -/* - The layout of a register frame looks like this: - - For - - function f(x, y) { - var v1; - function g() { } - var v2; - return (x) * (y); - } - - assuming (x) and (y) generated temporaries t1 and t2, you would have - - ------------------------------------ - | x | y | g | v2 | v1 | t1 | t2 | <-- value held - ------------------------------------ - | -5 | -4 | -3 | -2 | -1 | +0 | +1 | <-- register index - ------------------------------------ - | params->|<-locals | temps-> - - Because temporary registers are allocated in a stack-like fashion, we - can reclaim them with a simple popping algorithm. The same goes for labels. - (We never reclaim parameter or local registers, because parameters and - locals are DontDelete.) - - The register layout before a function call looks like this: - - For - - function f(x, y) - { - } - - f(1); - - > <------------------------------ - < > reserved: call frame | 1 | <-- value held - > >snip< <------------------------------ - < > +0 | +1 | +2 | +3 | +4 | +5 | <-- register index - > <------------------------------ - | params->|<-locals | temps-> - - The call instruction fills in the "call frame" registers. It also pads - missing arguments at the end of the call: - - > <----------------------------------- - < > reserved: call frame | 1 | ? | <-- value held ("?" stands for "undefined") - > >snip< <----------------------------------- - < > +0 | +1 | +2 | +3 | +4 | +5 | +6 | <-- register index - > <----------------------------------- - | params->|<-locals | temps-> - - After filling in missing arguments, the call instruction sets up the new - stack frame to overlap the end of the old stack frame: - - |----------------------------------> < - | reserved: call frame | 1 | ? < > <-- value held ("?" stands for "undefined") - |----------------------------------> >snip< < - | -7 | -6 | -5 | -4 | -3 | -2 | -1 < > <-- register index - |----------------------------------> < - | | params->|<-locals | temps-> - - That way, arguments are "copied" into the callee's stack frame for free. - - If the caller supplies too many arguments, this trick doesn't work. The - extra arguments protrude into space reserved for locals and temporaries. - In that case, the call instruction makes a real copy of the call frame header, - along with just the arguments expected by the callee, leaving the original - call frame header and arguments behind. (The call instruction can't just discard - extra arguments, because the "arguments" object may access them later.) - This copying strategy ensures that all named values will be at the indices - expected by the callee. -*/ - void Label::setLocation(unsigned location) { m_location = location; @@ -141,8 +67,12 @@ void ResolveResult::checkValidity() case Dynamic: ASSERT(!m_local); return; + case Lexical: + case ReadOnlyLexical: + ASSERT(!m_local); + return; default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } } #endif @@ -154,7 +84,9 @@ ParserError BytecodeGenerator::generate() m_codeBlock->setThisRegister(m_thisRegister.index()); m_scopeNode->emitBytecode(*this); - + + m_staticPropertyAnalyzer.kill(); + for (unsigned i = 0; i < m_tryRanges.size(); ++i) { TryRange& range = m_tryRanges[i]; int start = range.start->bind(); @@ -199,8 +131,8 @@ ParserError BytecodeGenerator::generate() m_codeBlock->shrinkToFit(); if (m_expressionTooDeep) - return ParserError::OutOfMemory; - return ParserError::ErrorNone; + return ParserError(ParserError::OutOfMemory); + return ParserError(ParserError::ErrorNone); } bool BytecodeGenerator::addVar(const Identifier& ident, bool isConstant, RegisterID*& r0) @@ -224,17 +156,15 @@ void BytecodeGenerator::preserveLastVar() m_lastVar = &m_calleeRegisters.last(); } -BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, ProgramNode* programNode, UnlinkedProgramCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode) +BytecodeGenerator::BytecodeGenerator(VM& vm, JSScope*, ProgramNode* programNode, UnlinkedProgramCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode) : m_shouldEmitDebugHooks(debuggerMode == DebuggerOn) , m_shouldEmitProfileHooks(profilerMode == ProfilerOn) -#if ENABLE(BYTECODE_COMMENTS) - , m_currentCommentString(0) -#endif , m_symbolTable(0) , m_scopeNode(programNode) - , m_codeBlock(globalData, codeBlock) + , m_codeBlock(vm, codeBlock) , m_thisRegister(CallFrame::thisArgumentOffset()) , m_emptyValueRegister(0) + , m_globalObjectRegister(0) , m_finallyDepth(0) , m_dynamicScopeDepth(0) , m_codeType(GlobalCode) @@ -243,12 +173,13 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, ProgramNode* prog , m_hasCreatedActivation(true) , m_firstLazyFunction(0) , m_lastLazyFunction(0) - , m_globalData(&globalData) + , m_staticPropertyAnalyzer(&m_instructions) + , m_vm(&vm) , m_lastOpcodeID(op_end) #ifndef NDEBUG , m_lastOpcodePosition(0) #endif - , m_stack(wtfThreadData().stack()) + , m_stack(vm, wtfThreadData().stack()) , m_usesExceptions(false) , m_expressionTooDeep(false) { @@ -257,7 +188,6 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, ProgramNode* prog m_codeBlock->setNumParameters(1); // Allocate space for "this" - prependComment("entering Program block"); emitOpcode(op_enter); const VarStack& varStack = programNode->varStack(); @@ -266,7 +196,7 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, ProgramNode* prog for (size_t i = 0; i < functionStack.size(); ++i) { FunctionBodyNode* function = functionStack[i]; UnlinkedFunctionExecutable* unlinkedFunction = makeFunction(function); - codeBlock->addFunctionDeclaration(*m_globalData, function->ident(), unlinkedFunction); + codeBlock->addFunctionDeclaration(*m_vm, function->ident(), unlinkedFunction); } for (size_t i = 0; i < varStack.size(); ++i) @@ -274,17 +204,16 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, ProgramNode* prog } -BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode* functionBody, UnlinkedFunctionCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode) +BytecodeGenerator::BytecodeGenerator(VM& vm, JSScope* scope, FunctionBodyNode* functionBody, UnlinkedFunctionCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode) : m_shouldEmitDebugHooks(debuggerMode == DebuggerOn) , m_shouldEmitProfileHooks(profilerMode == ProfilerOn) , m_symbolTable(codeBlock->symbolTable()) -#if ENABLE(BYTECODE_COMMENTS) - , m_currentCommentString(0) -#endif , m_scopeNode(functionBody) - , m_codeBlock(globalData, codeBlock) + , m_scope(vm, scope) + , m_codeBlock(vm, codeBlock) , m_activationRegister(0) , m_emptyValueRegister(0) + , m_globalObjectRegister(0) , m_finallyDepth(0) , m_dynamicScopeDepth(0) , m_codeType(FunctionCode) @@ -293,12 +222,13 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode* , m_hasCreatedActivation(false) , m_firstLazyFunction(0) , m_lastLazyFunction(0) - , m_globalData(&globalData) + , m_staticPropertyAnalyzer(&m_instructions) + , m_vm(&vm) , m_lastOpcodeID(op_end) #ifndef NDEBUG , m_lastOpcodePosition(0) #endif - , m_stack(wtfThreadData().stack()) + , m_stack(vm, wtfThreadData().stack()) , m_usesExceptions(false) , m_expressionTooDeep(false) { @@ -308,11 +238,9 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode* m_symbolTable->setUsesNonStrictEval(codeBlock->usesEval() && !codeBlock->isStrictMode()); m_symbolTable->setParameterCountIncludingThis(functionBody->parameters()->size() + 1); - prependComment("entering Function block"); emitOpcode(op_enter); if (m_codeBlock->needsFullScopeChain()) { m_activationRegister = addVar(); - prependComment("activation for Full Scope Chain"); emitInitLazyRegister(m_activationRegister); m_codeBlock->setActivationRegister(m_activationRegister->index()); } @@ -329,13 +257,10 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode* codeBlock->setArgumentsRegister(argumentsRegister->index()); ASSERT_UNUSED(unmodifiedArgumentsRegister, unmodifiedArgumentsRegister->index() == JSC::unmodifiedArgumentsRegister(codeBlock->argumentsRegister())); - prependComment("arguments for Full Scope Chain"); emitInitLazyRegister(argumentsRegister); - prependComment("unmodified arguments for Full Scope Chain"); emitInitLazyRegister(unmodifiedArgumentsRegister); if (m_codeBlock->isStrictMode()) { - prependComment("create arguments for strict mode"); emitOpcode(op_create_arguments); instructions().append(argumentsRegister->index()); } @@ -344,7 +269,6 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode* // it from a call frame. In the long-term it should stop doing that (), // but for now we force eager creation of the arguments object when debugging. if (m_shouldEmitDebugHooks) { - prependComment("create arguments for debug hooks"); emitOpcode(op_create_arguments); instructions().append(argumentsRegister->index()); } @@ -353,13 +277,13 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode* bool shouldCaptureAllTheThings = m_shouldEmitDebugHooks || codeBlock->usesEval(); bool capturesAnyArgumentByName = false; - Vector capturedArguments; + Vector capturedArguments; if (functionBody->hasCapturedVariables() || shouldCaptureAllTheThings) { FunctionParameters& parameters = *functionBody->parameters(); capturedArguments.resize(parameters.size()); for (size_t i = 0; i < parameters.size(); ++i) { capturedArguments[i] = 0; - if (!functionBody->captures(parameters[i]) && !shouldCaptureAllTheThings) + if (!functionBody->captures(parameters.at(i)) && !shouldCaptureAllTheThings) continue; capturesAnyArgumentByName = true; capturedArguments[i] = addVar(); @@ -396,12 +320,10 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode* if (functionBody->captures(ident)) { if (!m_hasCreatedActivation) { m_hasCreatedActivation = true; - prependComment("activation for captured vars"); emitOpcode(op_create_activation); instructions().append(m_activationRegister->index()); } m_functions.add(ident.impl()); - prependComment("captured function var"); emitNewFunction(addVar(ident, false), function); } } @@ -414,7 +336,6 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode* bool canLazilyCreateFunctions = !functionBody->needsActivationForMoreThanVariables() && !m_shouldEmitDebugHooks; if (!canLazilyCreateFunctions && !m_hasCreatedActivation) { m_hasCreatedActivation = true; - prependComment("cannot lazily create functions"); emitOpcode(op_create_activation); instructions().append(m_activationRegister->index()); } @@ -430,7 +351,6 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode* RefPtr reg = addVar(ident, false); // Don't lazily create functions that override the name 'arguments' // as this would complicate lazy instantiation of actual arguments. - prependComment("a function that override 'arguments'"); if (!canLazilyCreateFunctions || ident == propertyNames().arguments) emitNewFunction(reg.get(), function); else { @@ -460,12 +380,12 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode* for (size_t i = 0; i < parameters.size(); ++i, --nextParameterIndex) { int index = nextParameterIndex; if (capturedArguments.size() && capturedArguments[i]) { - ASSERT((functionBody->hasCapturedVariables() && functionBody->captures(parameters[i])) || shouldCaptureAllTheThings); + ASSERT((functionBody->hasCapturedVariables() && functionBody->captures(parameters.at(i))) || shouldCaptureAllTheThings); index = capturedArguments[i]->index(); RegisterID original(nextParameterIndex); emitMove(capturedArguments[i], &original); } - addParameter(parameters[i], index); + addParameter(parameters.at(i), index); } preserveLastVar(); @@ -473,35 +393,24 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, FunctionBodyNode* addCallee(functionBody, calleeRegister); if (isConstructor()) { - prependComment("'this' because we are a Constructor function"); - - RefPtr func = newTemporary(); - - UnlinkedValueProfile profile = emitProfiledOpcode(op_get_callee); - instructions().append(func->index()); - instructions().append(profile); - - emitOpcode(op_create_this); - instructions().append(m_thisRegister.index()); - instructions().append(func->index()); + emitCreateThis(&m_thisRegister); } else if (!codeBlock->isStrictMode() && (functionBody->usesThis() || codeBlock->usesEval() || m_shouldEmitDebugHooks)) { UnlinkedValueProfile profile = emitProfiledOpcode(op_convert_this); - instructions().append(m_thisRegister.index()); + instructions().append(kill(&m_thisRegister)); instructions().append(profile); } } -BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, EvalNode* evalNode, UnlinkedEvalCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode) +BytecodeGenerator::BytecodeGenerator(VM& vm, JSScope* scope, EvalNode* evalNode, UnlinkedEvalCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode) : m_shouldEmitDebugHooks(debuggerMode == DebuggerOn) , m_shouldEmitProfileHooks(profilerMode == ProfilerOn) , m_symbolTable(codeBlock->symbolTable()) -#if ENABLE(BYTECODE_COMMENTS) - , m_currentCommentString(0) -#endif , m_scopeNode(evalNode) - , m_codeBlock(globalData, codeBlock) + , m_scope(vm, scope) + , m_codeBlock(vm, codeBlock) , m_thisRegister(CallFrame::thisArgumentOffset()) , m_emptyValueRegister(0) + , m_globalObjectRegister(0) , m_finallyDepth(0) , m_dynamicScopeDepth(0) , m_codeType(EvalCode) @@ -510,12 +419,13 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, EvalNode* evalNod , m_hasCreatedActivation(true) , m_firstLazyFunction(0) , m_lastLazyFunction(0) - , m_globalData(&globalData) + , m_staticPropertyAnalyzer(&m_instructions) + , m_vm(&vm) , m_lastOpcodeID(op_end) #ifndef NDEBUG , m_lastOpcodePosition(0) #endif - , m_stack(wtfThreadData().stack()) + , m_stack(vm, wtfThreadData().stack()) , m_usesExceptions(false) , m_expressionTooDeep(false) { @@ -524,7 +434,6 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, EvalNode* evalNod m_symbolTable->setUsesNonStrictEval(codeBlock->usesEval() && !codeBlock->isStrictMode()); m_codeBlock->setNumParameters(1); - prependComment("entering Eval block"); emitOpcode(op_enter); const DeclarationStacks::FunctionStack& functionStack = evalNode->functionStack(); @@ -533,7 +442,7 @@ BytecodeGenerator::BytecodeGenerator(JSGlobalData& globalData, EvalNode* evalNod const DeclarationStacks::VarStack& varStack = evalNode->varStack(); unsigned numVariables = varStack.size(); - Vector variables; + Vector variables; variables.reserveCapacity(numVariables); for (size_t i = 0; i < numVariables; ++i) variables.append(*varStack[i].first); @@ -656,7 +565,7 @@ RegisterID* BytecodeGenerator::newTemporary() return result; } -PassRefPtr BytecodeGenerator::newLabelScope(LabelScope::Type type, const Identifier* name) +LabelScopePtr BytecodeGenerator::newLabelScope(LabelScope::Type type, const Identifier* name) { // Reclaim free label scopes. while (m_labelScopes.size() && !m_labelScopes.last().refCount()) @@ -665,7 +574,7 @@ PassRefPtr BytecodeGenerator::newLabelScope(LabelScope::Type type, c // Allocate new label scope. LabelScope scope(type, name, scopeDepth(), newLabel(), type == LabelScope::Loop ? newLabel() : PassRefPtr