summaryrefslogtreecommitdiffstats
path: root/JavaScriptCore/bytecompiler
diff options
context:
space:
mode:
Diffstat (limited to 'JavaScriptCore/bytecompiler')
-rw-r--r--JavaScriptCore/bytecompiler/BytecodeGenerator.cpp94
-rw-r--r--JavaScriptCore/bytecompiler/BytecodeGenerator.h13
-rw-r--r--JavaScriptCore/bytecompiler/NodesCodegen.cpp18
3 files changed, 102 insertions, 23 deletions
diff --git a/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index 986709b..f34c38c 100644
--- a/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -214,6 +214,7 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, const Debugger* d
, m_nextGlobalIndex(-1)
, m_nextConstantOffset(0)
, m_globalConstantIndex(0)
+ , m_hasCreatedActivation(true)
, m_firstLazyFunction(0)
, m_lastLazyFunction(0)
, m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
@@ -306,10 +307,14 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debug
, m_codeType(FunctionCode)
, m_nextConstantOffset(0)
, m_globalConstantIndex(0)
+ , m_hasCreatedActivation(false)
, m_firstLazyFunction(0)
, m_lastLazyFunction(0)
, m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
, m_lastOpcodeID(op_end)
+#ifndef NDEBUG
+ , m_lastOpcodePosition(0)
+#endif
, m_emitNodeDepth(0)
, m_usesExceptions(false)
, m_regeneratingForExceptionInfo(false)
@@ -319,13 +324,13 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debug
m_codeBlock->setNeedsFullScopeChain(true);
codeBlock->setGlobalData(m_globalData);
-
+
+ emitOpcode(op_enter);
if (m_codeBlock->needsFullScopeChain()) {
m_activationRegister = addVar();
- emitOpcode(op_enter_with_activation);
- instructions().append(m_activationRegister->index());
- } else
- emitOpcode(op_enter);
+ emitInitLazyRegister(m_activationRegister);
+ m_codeBlock->setActivationRegister(m_activationRegister->index());
+ }
// Both op_tear_off_activation and op_tear_off_arguments tear off the 'arguments'
// object, if created.
@@ -341,6 +346,11 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debug
emitInitLazyRegister(argumentsRegister);
emitInitLazyRegister(unmodifiedArgumentsRegister);
+
+ if (m_codeBlock->isStrictMode()) {
+ emitOpcode(op_create_arguments);
+ instructions().append(argumentsRegister->index());
+ }
// The debugger currently retrieves the arguments object from an activation rather than pulling
// it from a call frame. In the long-term it should stop doing that (<rdar://problem/6911886>),
@@ -356,11 +366,17 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debug
// Captured variables and functions go first so that activations don't have
// to step over the non-captured locals to mark them.
+ m_hasCreatedActivation = false;
if (functionBody->hasCapturedVariables()) {
for (size_t i = 0; i < functionStack.size(); ++i) {
FunctionBodyNode* function = functionStack[i];
const Identifier& ident = function->ident();
if (functionBody->captures(ident)) {
+ if (!m_hasCreatedActivation) {
+ m_hasCreatedActivation = true;
+ emitOpcode(op_create_activation);
+ instructions().append(m_activationRegister->index());
+ }
m_functions.add(ident.impl());
emitNewFunction(addVar(ident, false), function);
}
@@ -371,7 +387,13 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debug
addVar(ident, varStack[i].second & DeclarationStacks::IsConstant);
}
}
- bool canLazilyCreateFunctions = !functionBody->needsActivationForMoreThanVariables();
+ bool canLazilyCreateFunctions = !functionBody->needsActivationForMoreThanVariables() && !debugger;
+ if (!canLazilyCreateFunctions && !m_hasCreatedActivation) {
+ m_hasCreatedActivation = true;
+ emitOpcode(op_create_activation);
+ instructions().append(m_activationRegister->index());
+ }
+
codeBlock->m_numCapturedVars = codeBlock->m_numVars;
m_firstLazyFunction = codeBlock->m_numVars;
for (size_t i = 0; i < functionStack.size(); ++i) {
@@ -399,7 +421,6 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debug
if (debugger)
codeBlock->m_numCapturedVars = codeBlock->m_numVars;
-
FunctionParameters& parameters = *functionBody->parameters();
size_t parameterCount = parameters.size();
@@ -429,7 +450,10 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debug
instructions().append(m_thisRegister.index());
instructions().append(funcProto->index());
} else if (functionBody->usesThis() || m_shouldEmitDebugHooks) {
- emitOpcode(op_convert_this);
+ if (codeBlock->isStrictMode())
+ emitOpcode(op_convert_this_strict);
+ else
+ emitOpcode(op_convert_this);
instructions().append(m_thisRegister.index());
}
}
@@ -448,10 +472,14 @@ BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, const Debugger* debugge
, m_codeType(EvalCode)
, m_nextConstantOffset(0)
, m_globalConstantIndex(0)
+ , m_hasCreatedActivation(true)
, m_firstLazyFunction(0)
, m_lastLazyFunction(0)
, m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
, m_lastOpcodeID(op_end)
+#ifndef NDEBUG
+ , m_lastOpcodePosition(0)
+#endif
, m_emitNodeDepth(0)
, m_usesExceptions(false)
, m_regeneratingForExceptionInfo(false)
@@ -1249,6 +1277,7 @@ RegisterID* BytecodeGenerator::emitResolveBase(RegisterID* dst, const Identifier
emitOpcode(op_resolve_base);
instructions().append(dst->index());
instructions().append(addConstant(property));
+ instructions().append(false);
return dst;
}
@@ -1256,6 +1285,32 @@ RegisterID* BytecodeGenerator::emitResolveBase(RegisterID* dst, const Identifier
return emitLoad(dst, JSValue(globalObject));
}
+RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const Identifier& property)
+{
+ if (!m_codeBlock->isStrictMode())
+ return emitResolveBase(dst, property);
+ size_t depth = 0;
+ int index = 0;
+ JSObject* globalObject = 0;
+ bool requiresDynamicChecks = false;
+ findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject);
+ if (!globalObject || requiresDynamicChecks) {
+ // We can't optimise at all :-(
+ emitOpcode(op_resolve_base);
+ instructions().append(dst->index());
+ instructions().append(addConstant(property));
+ instructions().append(true);
+ return dst;
+ }
+
+ // Global object is the base
+ RefPtr<RegisterID> result = emitLoad(dst, JSValue(globalObject));
+ emitOpcode(op_ensure_property_exists);
+ instructions().append(dst->index());
+ instructions().append(addConstant(property));
+ return result.get();
+}
+
RegisterID* BytecodeGenerator::emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property)
{
size_t depth = 0;
@@ -1504,6 +1559,7 @@ RegisterID* BytecodeGenerator::emitLazyNewFunction(RegisterID* dst, FunctionBody
RegisterID* BytecodeGenerator::emitNewFunctionInternal(RegisterID* dst, unsigned index, bool doNullCheck)
{
+ createActivationIfNecessary();
emitOpcode(op_new_func);
instructions().append(dst->index());
instructions().append(index);
@@ -1523,7 +1579,8 @@ RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* r0, FuncExp
{
FunctionBodyNode* function = n->body();
unsigned index = m_codeBlock->addFunctionExpr(makeFunction(m_globalData, function));
-
+
+ createActivationIfNecessary();
emitOpcode(op_new_func_exp);
instructions().append(r0->index());
instructions().append(index);
@@ -1541,10 +1598,26 @@ void BytecodeGenerator::createArgumentsIfNecessary()
return;
ASSERT(m_codeBlock->usesArguments());
+ // If we're in strict mode we tear off the arguments on function
+ // entry, so there's no need to check if we need to create them
+ // now
+ if (m_codeBlock->isStrictMode())
+ return;
+
emitOpcode(op_create_arguments);
instructions().append(m_codeBlock->argumentsRegister());
}
+void BytecodeGenerator::createActivationIfNecessary()
+{
+ if (m_hasCreatedActivation)
+ return;
+ if (!m_codeBlock->needsFullScopeChain())
+ return;
+ emitOpcode(op_create_activation);
+ instructions().append(m_activationRegister->index());
+}
+
RegisterID* BytecodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset)
{
return emitCall(op_call_eval, dst, func, callArguments, divot, startOffset, endOffset);
@@ -1648,7 +1721,8 @@ RegisterID* BytecodeGenerator::emitReturn(RegisterID* src)
emitOpcode(op_tear_off_activation);
instructions().append(m_activationRegister->index());
instructions().append(m_codeBlock->argumentsRegister());
- } else if (m_codeBlock->usesArguments() && m_codeBlock->m_numParameters > 1) { // If there are no named parameters, there's nothing to tear off, since extra / unnamed parameters get copied to the arguments object at construct time.
+ } else if (m_codeBlock->usesArguments() && m_codeBlock->m_numParameters > 1
+ && !m_codeBlock->isStrictMode()) { // If there are no named parameters, there's nothing to tear off, since extra / unnamed parameters get copied to the arguments object at construct time.
emitOpcode(op_tear_off_arguments);
instructions().append(m_codeBlock->argumentsRegister());
}
diff --git a/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index 2afa0c4..d0e4a6b 100644
--- a/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -329,6 +329,7 @@ namespace JSC {
RegisterID* emitPutScopedVar(size_t skip, int index, RegisterID* value, JSValue globalObject);
RegisterID* emitResolveBase(RegisterID* dst, const Identifier& property);
+ RegisterID* emitResolveBaseForPut(RegisterID* dst, const Identifier& property);
RegisterID* emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property);
void emitMethodCheck();
@@ -419,13 +420,15 @@ namespace JSC {
}
bool shouldEmitProfileHooks() { return m_shouldEmitProfileHooks; }
+
+ bool isStrictMode() const { return m_codeBlock->isStrictMode(); }
private:
void emitOpcode(OpcodeID);
void retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index);
void retrieveLastUnaryOp(int& dstIndex, int& srcIndex);
- void rewindBinaryOp();
- void rewindUnaryOp();
+ ALWAYS_INLINE void rewindBinaryOp();
+ ALWAYS_INLINE void rewindUnaryOp();
PassRefPtr<Label> emitComplexJumpScopes(Label* target, ControlFlowContext* topScope, ControlFlowContext* bottomScope);
@@ -499,12 +502,12 @@ namespace JSC {
PassRefPtr<FunctionExecutable> makeFunction(ExecState* exec, FunctionBodyNode* body)
{
- return FunctionExecutable::create(exec, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->lineNo(), body->lastLine());
+ return FunctionExecutable::create(exec, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
}
PassRefPtr<FunctionExecutable> makeFunction(JSGlobalData* globalData, FunctionBodyNode* body)
{
- return FunctionExecutable::create(globalData, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->lineNo(), body->lastLine());
+ return FunctionExecutable::create(globalData, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
}
RegisterID* emitInitLazyRegister(RegisterID*);
@@ -518,6 +521,7 @@ namespace JSC {
RegisterID* emitThrowExpressionTooDeepException();
void createArgumentsIfNecessary();
+ void createActivationIfNecessary();
RegisterID* createLazyRegisterIfNecessary(RegisterID*);
bool m_shouldEmitDebugHooks;
@@ -558,6 +562,7 @@ namespace JSC {
int m_globalVarStorageOffset;
+ bool m_hasCreatedActivation;
int m_firstLazyFunction;
int m_lastLazyFunction;
HashMap<unsigned int, FunctionBodyNode*, WTF::IntHash<unsigned int>, WTF::UnsignedWithZeroKeyHashTraits<unsigned int> > m_lazyFunctions;
diff --git a/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index 2cc1a3f..449cae9 100644
--- a/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -42,7 +42,7 @@
#include "RegExpCache.h"
#include "RegExpObject.h"
#include "SamplingTool.h"
-#include "StringConcatenate.h"
+#include "UStringConcatenate.h"
#include <wtf/Assertions.h>
#include <wtf/RefCountedLeakCounter.h>
#include <wtf/Threading.h>
@@ -80,7 +80,7 @@ static void substitute(UString& string, const UString& substring)
{
size_t position = string.find("%s");
ASSERT(position != notFound);
- string = makeString(string.substringSharingImpl(0, position), substring, string.substringSharingImpl(position + 2));
+ string = makeUString(string.substringSharingImpl(0, position), substring, string.substringSharingImpl(position + 2));
}
RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, bool isReferenceError, const char* message)
@@ -371,7 +371,7 @@ RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, Re
{
RefPtr<RegisterID> func = generator.emitNode(m_expr);
CallArguments callArguments(generator, m_args);
- generator.emitLoad(callArguments.thisRegister(), jsNull());
+ generator.emitLoad(callArguments.thisRegister(), jsUndefined());
return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset());
}
@@ -381,7 +381,7 @@ RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator,
{
if (RefPtr<RegisterID> local = generator.registerFor(m_ident)) {
CallArguments callArguments(generator, m_args);
- generator.emitLoad(callArguments.thisRegister(), jsNull());
+ generator.emitLoad(callArguments.thisRegister(), jsUndefined());
return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), local.get(), callArguments, divot(), startOffset(), endOffset());
}
@@ -392,7 +392,7 @@ RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator,
if (generator.findScopedProperty(m_ident, index, depth, false, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) {
RefPtr<RegisterID> func = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject);
CallArguments callArguments(generator, m_args);
- generator.emitLoad(callArguments.thisRegister(), jsNull());
+ generator.emitLoad(callArguments.thisRegister(), jsUndefined());
return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset());
}
@@ -455,7 +455,7 @@ RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator,
} else {
RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get());
CallArguments callArguments(generator, m_args);
- generator.emitLoad(callArguments.thisRegister(), jsNull());
+ generator.emitLoad(callArguments.thisRegister(), jsUndefined());
generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), callArguments, divot(), startOffset(), endOffset());
generator.emitJump(end.get());
}
@@ -513,7 +513,7 @@ RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator,
} else {
RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get());
CallArguments callArguments(generator, m_args);
- generator.emitLoad(callArguments.thisRegister(), jsNull());
+ generator.emitLoad(callArguments.thisRegister(), jsUndefined());
generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), callArguments, divot(), startOffset(), endOffset());
}
} else {
@@ -1231,7 +1231,7 @@ RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, Regist
return value;
}
- RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), m_ident);
+ RefPtr<RegisterID> base = generator.emitResolveBaseForPut(generator.newTemporary(), m_ident);
if (dst == generator.ignoredResult())
dst = 0;
RegisterID* value = generator.emitNode(dst, m_right);
@@ -1605,7 +1605,7 @@ RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds
if (!propertyName) {
propertyName = generator.newTemporary();
RefPtr<RegisterID> protect = propertyName;
- RegisterID* base = generator.emitResolveBase(generator.newTemporary(), ident);
+ RegisterID* base = generator.emitResolveBaseForPut(generator.newTemporary(), ident);
generator.emitExpressionInfo(divot(), startOffset(), endOffset());
generator.emitPutById(base, ident, propertyName);