diff options
Diffstat (limited to 'Source/JavaScriptCore/bytecompiler')
-rw-r--r-- | Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp | 97 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h | 20 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp | 36 |
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(); |