summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/bytecompiler
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2012-10-18 10:55:06 +0200
committerSimon Hausmann <simon.hausmann@digia.com>2012-10-18 10:55:06 +0200
commitee4c86d1990a9e26277a6948e7027ad8d525ebfa (patch)
tree1e2d3408cd097606571f40ab63353c27bcb7dd5c /Source/JavaScriptCore/bytecompiler
parentd882bec96d0d30aeeda2141bfadfca7f038ee862 (diff)
downloadqtwebkit-ee4c86d1990a9e26277a6948e7027ad8d525ebfa.tar.gz
Imported WebKit commit 795dcd25a9649fccaf1c9b685f6e2ffedaf7e620 (http://svn.webkit.org/repository/webkit/trunk@131718)
New snapshot that includes the return of -fkeep-memory at link time to reduce memory pressure as well as modularized documentation
Diffstat (limited to 'Source/JavaScriptCore/bytecompiler')
-rw-r--r--Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp97
-rw-r--r--Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h20
-rw-r--r--Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp36
3 files changed, 130 insertions, 23 deletions
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index 4308148b3..1160a1888 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -2013,9 +2013,9 @@ RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* r0, FuncExp
return r0;
}
-RegisterID* BytecodeGenerator::emitCall(RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset)
+RegisterID* BytecodeGenerator::emitCall(RegisterID* dst, RegisterID* func, ExpectedFunction expectedFunction, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset)
{
- return emitCall(op_call, dst, func, callArguments, divot, startOffset, endOffset);
+ return emitCall(op_call, dst, func, expectedFunction, callArguments, divot, startOffset, endOffset);
}
void BytecodeGenerator::createArgumentsIfNecessary()
@@ -2048,10 +2048,85 @@ void BytecodeGenerator::createActivationIfNecessary()
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);
+ return emitCall(op_call_eval, dst, func, NoExpectedFunction, callArguments, divot, startOffset, endOffset);
}
-RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset)
+ExpectedFunction BytecodeGenerator::expectedFunctionForIdentifier(const Identifier& identifier)
+{
+ if (identifier == m_globalData->propertyNames->Object)
+ return ExpectObjectConstructor;
+ if (identifier == m_globalData->propertyNames->Array)
+ return ExpectArrayConstructor;
+ return NoExpectedFunction;
+}
+
+ExpectedFunction BytecodeGenerator::emitExpectedFunctionSnippet(RegisterID* dst, RegisterID* func, ExpectedFunction expectedFunction, CallArguments& callArguments, Label* done)
+{
+ RefPtr<Label> realCall = newLabel();
+ switch (expectedFunction) {
+ case ExpectObjectConstructor: {
+ // If the number of arguments is non-zero, then we can't do anything interesting.
+ if (callArguments.argumentCountIncludingThis() >= 2)
+ return NoExpectedFunction;
+
+ size_t begin = instructions().size();
+ emitOpcode(op_jneq_ptr);
+ instructions().append(func->index());
+ instructions().append(Special::ObjectConstructor);
+ instructions().append(realCall->bind(begin, instructions().size()));
+
+ if (dst != ignoredResult()) {
+ emitOpcode(op_new_object);
+ instructions().append(dst->index());
+ }
+ break;
+ }
+
+ case ExpectArrayConstructor: {
+ // If you're doing anything other than "new Array()" or "new Array(foo)" then we
+ // don't do inline it, for now. The only reason is that call arguments are in
+ // the opposite order of what op_new_array expects, so we'd either need to change
+ // how op_new_array works or we'd need an op_new_array_reverse. Neither of these
+ // things sounds like it's worth it.
+ if (callArguments.argumentCountIncludingThis() > 2)
+ return NoExpectedFunction;
+
+ size_t begin = instructions().size();
+ emitOpcode(op_jneq_ptr);
+ instructions().append(func->index());
+ instructions().append(Special::ArrayConstructor);
+ instructions().append(realCall->bind(begin, instructions().size()));
+
+ if (dst != ignoredResult()) {
+ if (callArguments.argumentCountIncludingThis() == 2) {
+ emitOpcode(op_new_array_with_size);
+ instructions().append(dst->index());
+ instructions().append(callArguments.argumentRegister(0)->index());
+ } else {
+ ASSERT(callArguments.argumentCountIncludingThis() == 1);
+ emitOpcode(op_new_array);
+ instructions().append(dst->index());
+ instructions().append(0);
+ instructions().append(0);
+ }
+ }
+ break;
+ }
+
+ default:
+ ASSERT(expectedFunction == NoExpectedFunction);
+ return NoExpectedFunction;
+ }
+
+ size_t begin = instructions().size();
+ emitOpcode(op_jmp);
+ instructions().append(done->bind(begin, instructions().size()));
+ emitLabel(realCall.get());
+
+ return expectedFunction;
+}
+
+RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, RegisterID* func, ExpectedFunction expectedFunction, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset)
{
ASSERT(opcodeID == op_call || opcodeID == op_call_eval);
ASSERT(func->refCount());
@@ -2076,6 +2151,9 @@ RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Regi
emitExpressionInfo(divot, startOffset, endOffset);
+ RefPtr<Label> done = newLabel();
+ expectedFunction = emitExpectedFunctionSnippet(dst, func, expectedFunction, callArguments, done.get());
+
// Emit call.
ArrayProfile* arrayProfile = newArrayProfile();
emitOpcode(opcodeID);
@@ -2093,6 +2171,9 @@ RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Regi
instructions().append(dst->index()); // dst
instructions().append(profile);
}
+
+ if (expectedFunction != NoExpectedFunction)
+ emitLabel(done.get());
if (m_shouldEmitProfileHooks) {
emitOpcode(op_profile_did_call);
@@ -2162,7 +2243,7 @@ RegisterID* BytecodeGenerator::emitUnaryNoDstOp(OpcodeID opcodeID, RegisterID* s
return src;
}
-RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset)
+RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, ExpectedFunction expectedFunction, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset)
{
ASSERT(func->refCount());
@@ -2187,6 +2268,9 @@ RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func,
callFrame.append(newTemporary());
emitExpressionInfo(divot, startOffset, endOffset);
+
+ RefPtr<Label> done = newLabel();
+ expectedFunction = emitExpectedFunctionSnippet(dst, func, expectedFunction, callArguments, done.get());
emitOpcode(op_construct);
instructions().append(func->index()); // func
@@ -2204,6 +2288,9 @@ RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func,
instructions().append(profile);
}
+ if (expectedFunction != NoExpectedFunction)
+ emitLabel(done.get());
+
if (m_shouldEmitProfileHooks) {
emitOpcode(op_profile_did_call);
instructions().append(callArguments.profileHookRegister()->index());
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index a429c710e..ae79a13ae 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -51,6 +51,12 @@ namespace JSC {
class Label;
class JSScope;
+ enum ExpectedFunction {
+ NoExpectedFunction,
+ ExpectObjectConstructor,
+ ExpectArrayConstructor
+ };
+
class CallArguments {
public:
CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode);
@@ -483,8 +489,9 @@ namespace JSC {
RegisterID* emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
RegisterID* emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value);
void emitPutGetterSetter(RegisterID* base, const Identifier& property, RegisterID* getter, RegisterID* setter);
-
- RegisterID* emitCall(RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ ExpectedFunction expectedFunctionForIdentifier(const Identifier&);
+ RegisterID* emitCall(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset);
RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset);
RegisterID* emitCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, RegisterID* profileHookRegister, unsigned divot, unsigned startOffset, unsigned endOffset);
RegisterID* emitLoadVarargs(RegisterID* argCountDst, RegisterID* thisRegister, RegisterID* args);
@@ -492,7 +499,7 @@ namespace JSC {
RegisterID* emitReturn(RegisterID* src);
RegisterID* emitEnd(RegisterID* src) { return emitUnaryNoDstOp(op_end, src); }
- RegisterID* emitConstruct(RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset);
+ RegisterID* emitConstruct(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset);
RegisterID* emitStrcat(RegisterID* dst, RegisterID* src, int count);
void emitToPrimitive(RegisterID* dst, RegisterID* src);
@@ -590,7 +597,12 @@ namespace JSC {
typedef HashMap<double, JSValue> NumberMap;
typedef HashMap<StringImpl*, JSString*, IdentifierRepHash> IdentifierStringMap;
- RegisterID* emitCall(OpcodeID, RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset);
+ // Helper for emitCall() and emitConstruct(). This works because the set of
+ // expected functions have identical behavior for both call and construct
+ // (i.e. "Object()" is identical to "new Object()").
+ ExpectedFunction emitExpectedFunctionSnippet(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, Label* done);
+
+ RegisterID* emitCall(OpcodeID, RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset);
RegisterID* newRegister();
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index 0ac4149b6..10a873d1c 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -366,9 +366,14 @@ RegisterID* ArgumentListNode::emitBytecode(BytecodeGenerator& generator, Registe
RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
+ ExpectedFunction expectedFunction;
+ if (m_expr->isResolveNode())
+ expectedFunction = generator.expectedFunctionForIdentifier(static_cast<ResolveNode*>(m_expr)->identifier());
+ else
+ expectedFunction = NoExpectedFunction;
RefPtr<RegisterID> func = generator.emitNode(m_expr);
CallArguments callArguments(generator, m_args);
- return generator.emitConstruct(generator.finalDestinationOrIgnored(dst), func.get(), callArguments, divot(), startOffset(), endOffset());
+ return generator.emitConstruct(generator.finalDestinationOrIgnored(dst), func.get(), expectedFunction, callArguments, divot(), startOffset(), endOffset());
}
inline CallArguments::CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode)
@@ -415,20 +420,23 @@ RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, Re
RefPtr<RegisterID> func = generator.emitNode(m_expr);
CallArguments callArguments(generator, m_args);
generator.emitLoad(callArguments.thisRegister(), jsUndefined());
- return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset());
+ return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset());
}
// ------------------------------ FunctionCallResolveNode ----------------------------------
RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
+ ExpectedFunction expectedFunction = generator.expectedFunctionForIdentifier(m_ident);
ResolveResult resolveResult = generator.resolve(m_ident);
if (RegisterID* local = resolveResult.local()) {
RefPtr<RegisterID> func = generator.emitMove(generator.tempDestination(dst), local);
CallArguments callArguments(generator, m_args);
generator.emitLoad(callArguments.thisRegister(), jsUndefined());
- return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), func.get(), callArguments, divot(), startOffset(), endOffset());
+ // This passes NoExpectedFunction because we expect that if the function is in a
+ // local variable, then it's not one of our built-in constructors.
+ return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), func.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset());
}
if (resolveResult.isStatic()) {
@@ -436,7 +444,7 @@ RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator,
CallArguments callArguments(generator, m_args);
generator.emitGetStaticVar(func.get(), resolveResult, m_ident);
generator.emitLoad(callArguments.thisRegister(), jsUndefined());
- return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset());
+ return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), expectedFunction, callArguments, divot(), startOffset(), endOffset());
}
RefPtr<RegisterID> func = generator.newTemporary();
@@ -445,7 +453,7 @@ RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator,
generator.emitExpressionInfo(identifierStart + m_ident.length(), m_ident.length(), 0);
generator.emitResolveWithThis(callArguments.thisRegister(), func.get(), resolveResult, m_ident);
- return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset());
+ return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), expectedFunction, callArguments, divot(), startOffset(), endOffset());
}
// ------------------------------ FunctionCallBracketNode ----------------------------------
@@ -458,7 +466,7 @@ RegisterID* FunctionCallBracketNode::emitBytecode(BytecodeGenerator& generator,
RefPtr<RegisterID> function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property);
CallArguments callArguments(generator, m_args);
generator.emitMove(callArguments.thisRegister(), base.get());
- return generator.emitCall(generator.finalDestinationOrIgnored(dst, function.get()), function.get(), callArguments, divot(), startOffset(), endOffset());
+ return generator.emitCall(generator.finalDestinationOrIgnored(dst, function.get()), function.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset());
}
// ------------------------------ FunctionCallDotNode ----------------------------------
@@ -471,7 +479,7 @@ RegisterID* FunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, Regi
generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset);
generator.emitMethodCheck();
generator.emitGetById(function.get(), callArguments.thisRegister(), m_ident);
- return generator.emitCall(generator.finalDestinationOrIgnored(dst, function.get()), function.get(), callArguments, divot(), startOffset(), endOffset());
+ return generator.emitCall(generator.finalDestinationOrIgnored(dst, function.get()), function.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset());
}
RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
@@ -491,7 +499,7 @@ RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator,
RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get());
CallArguments callArguments(generator, m_args);
generator.emitNode(callArguments.thisRegister(), oldList->m_expr);
- generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), callArguments, divot(), startOffset(), endOffset());
+ generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset());
generator.emitJump(end.get());
m_args->m_listNode = oldList;
@@ -499,7 +507,7 @@ RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator,
RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get());
CallArguments callArguments(generator, m_args);
generator.emitLoad(callArguments.thisRegister(), jsUndefined());
- generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), callArguments, divot(), startOffset(), endOffset());
+ generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset());
generator.emitJump(end.get());
}
}
@@ -507,7 +515,7 @@ RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator,
{
CallArguments callArguments(generator, m_args);
generator.emitMove(callArguments.thisRegister(), base.get());
- generator.emitCall(finalDestinationOrIgnored.get(), function.get(), callArguments, divot(), startOffset(), endOffset());
+ generator.emitCall(finalDestinationOrIgnored.get(), function.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset());
}
generator.emitLabel(end.get());
return finalDestinationOrIgnored.get();
@@ -544,20 +552,20 @@ RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator,
RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get());
CallArguments callArguments(generator, m_args);
generator.emitNode(callArguments.thisRegister(), oldList->m_expr);
- generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), callArguments, divot(), startOffset(), endOffset());
+ generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset());
} else {
m_args->m_listNode = m_args->m_listNode->m_next;
RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get());
CallArguments callArguments(generator, m_args);
generator.emitNode(callArguments.thisRegister(), oldList->m_expr);
- generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), callArguments, divot(), startOffset(), endOffset());
+ generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset());
}
m_args->m_listNode = oldList;
} else {
RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get());
CallArguments callArguments(generator, m_args);
generator.emitLoad(callArguments.thisRegister(), jsUndefined());
- generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), callArguments, divot(), startOffset(), endOffset());
+ generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset());
}
} else {
ASSERT(m_args->m_listNode && m_args->m_listNode->m_next);
@@ -586,7 +594,7 @@ RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator,
{
CallArguments callArguments(generator, m_args);
generator.emitMove(callArguments.thisRegister(), base.get());
- generator.emitCall(finalDestinationOrIgnored.get(), function.get(), callArguments, divot(), startOffset(), endOffset());
+ generator.emitCall(finalDestinationOrIgnored.get(), function.get(), NoExpectedFunction, callArguments, divot(), startOffset(), endOffset());
}
generator.emitLabel(end.get());
return finalDestinationOrIgnored.get();