[Interpreter] Add function literal support.
Adds function literal support and add support for OTHER_CALLS which can be made when calling a function literal. Adds the CreateClosure bytecode. BUG=v8:4280 LOG=N Review URL: https://codereview.chromium.org/1396693003 Cr-Commit-Position: refs/heads/master@{#31231}
This commit is contained in:
parent
e5320d8a59
commit
66e5937337
@ -315,6 +315,12 @@ void BytecodeGraphBuilder::VisitKeyedStoreICStrict(
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitCreateClosure(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitCall(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
UNIMPLEMENTED();
|
||||
|
@ -322,6 +322,14 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty(
|
||||
}
|
||||
|
||||
|
||||
BytecodeArrayBuilder& BytecodeArrayBuilder::CreateClosure(
|
||||
PretenureFlag tenured) {
|
||||
DCHECK(FitsInImm8Operand(tenured));
|
||||
Output(Bytecode::kCreateClosure, static_cast<uint8_t>(tenured));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToBoolean() {
|
||||
if (LastBytecodeInSameBlock()) {
|
||||
// If the previous bytecode puts a boolean in the accumulator
|
||||
|
@ -72,6 +72,9 @@ class BytecodeArrayBuilder {
|
||||
int feedback_slot,
|
||||
LanguageMode language_mode);
|
||||
|
||||
// Create a new closure for the SharedFunctionInfo in the accumulator.
|
||||
BytecodeArrayBuilder& CreateClosure(PretenureFlag tenured);
|
||||
|
||||
// Call a JS function. The JSFunction or Callable to be called should be in
|
||||
// |callable|, the receiver should be in |receiver| and all subsequent
|
||||
// arguments should be in registers <receiver + 1> to
|
||||
|
@ -394,7 +394,14 @@ void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
|
||||
|
||||
|
||||
void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
|
||||
UNIMPLEMENTED();
|
||||
// Find or build a shared function info.
|
||||
Handle<SharedFunctionInfo> shared_info =
|
||||
Compiler::GetSharedFunctionInfo(expr, info()->script(), info());
|
||||
CHECK(!shared_info.is_null()); // TODO(rmcilroy): Set stack overflow?
|
||||
|
||||
builder()
|
||||
->LoadLiteral(shared_info)
|
||||
.CreateClosure(expr->pretenure() ? TENURED : NOT_TENURED);
|
||||
}
|
||||
|
||||
|
||||
@ -679,10 +686,15 @@ void BytecodeGenerator::VisitCall(Call* expr) {
|
||||
builder()->StoreAccumulatorInRegister(callee);
|
||||
break;
|
||||
}
|
||||
case Call::OTHER_CALL: {
|
||||
builder()->LoadUndefined().StoreAccumulatorInRegister(receiver);
|
||||
Visit(callee_expr);
|
||||
builder()->StoreAccumulatorInRegister(callee);
|
||||
break;
|
||||
}
|
||||
case Call::LOOKUP_SLOT_CALL:
|
||||
case Call::SUPER_CALL:
|
||||
case Call::POSSIBLY_EVAL_CALL:
|
||||
case Call::OTHER_CALL:
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
@ -105,6 +105,9 @@ namespace interpreter {
|
||||
/* Cast operators */ \
|
||||
V(ToBoolean, OperandType::kNone) \
|
||||
\
|
||||
/* Closure allocation */ \
|
||||
V(CreateClosure, OperandType::kImm8) \
|
||||
\
|
||||
/* Control Flow */ \
|
||||
V(Jump, OperandType::kImm8) \
|
||||
V(JumpConstant, OperandType::kIdx8) \
|
||||
|
@ -687,6 +687,23 @@ void Interpreter::DoJumpIfFalseConstant(
|
||||
}
|
||||
|
||||
|
||||
// CreateClosure <tenured>
|
||||
//
|
||||
// Creates a new closure for SharedFunctionInfo in the accumulator with the
|
||||
// PretenureFlag <tenured>.
|
||||
void Interpreter::DoCreateClosure(compiler::InterpreterAssembler* assembler) {
|
||||
// TODO(rmcilroy): Possibly call FastNewClosureStub when possible instead of
|
||||
// calling into the runtime.
|
||||
Node* shared = __ GetAccumulator();
|
||||
Node* tenured_raw = __ BytecodeOperandImm8(0);
|
||||
Node* tenured = __ SmiTag(tenured_raw);
|
||||
Node* result =
|
||||
__ CallRuntime(Runtime::kInterpreterNewClosure, shared, tenured);
|
||||
__ SetAccumulator(result);
|
||||
__ Dispatch();
|
||||
}
|
||||
|
||||
|
||||
// Return
|
||||
//
|
||||
// Return the value in the accumulator.
|
||||
|
@ -137,5 +137,15 @@ RUNTIME_FUNCTION(Runtime_InterpreterTypeOf) {
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_InterpreterNewClosure) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(2, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
|
||||
CONVERT_SMI_ARG_CHECKED(pretenured_flag, 1);
|
||||
Handle<Context> context(isolate->context(), isolate);
|
||||
return *isolate->factory()->NewFunctionFromSharedFunctionInfo(
|
||||
shared, context, static_cast<PretenureFlag>(pretenured_flag));
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -227,7 +227,8 @@ namespace internal {
|
||||
F(InterpreterGreaterThanOrEqual, 2, 1) \
|
||||
F(InterpreterToBoolean, 1, 1) \
|
||||
F(InterpreterLogicalNot, 1, 1) \
|
||||
F(InterpreterTypeOf, 1, 1)
|
||||
F(InterpreterTypeOf, 1, 1) \
|
||||
F(InterpreterNewClosure, 2, 1)
|
||||
|
||||
|
||||
#define FOR_EACH_INTRINSIC_FUNCTION(F) \
|
||||
|
@ -121,6 +121,11 @@ static void CheckConstant(Handle<Object> expected, Object* actual) {
|
||||
}
|
||||
|
||||
|
||||
static void CheckConstant(InstanceType expected, Object* actual) {
|
||||
CHECK_EQ(expected, HeapObject::cast(actual)->map()->instance_type());
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
static void CheckBytecodeArrayEqual(struct ExpectedSnippet<T> expected,
|
||||
Handle<BytecodeArray> actual,
|
||||
@ -1813,6 +1818,63 @@ TEST(UnaryOperators) {
|
||||
}
|
||||
|
||||
|
||||
TEST(FunctionLiterals) {
|
||||
InitializedHandleScope handle_scope;
|
||||
BytecodeGeneratorHelper helper;
|
||||
|
||||
ExpectedSnippet<InstanceType> snippets[] = {
|
||||
{"return function(){ }",
|
||||
0,
|
||||
1,
|
||||
5,
|
||||
{
|
||||
B(LdaConstant), U8(0), //
|
||||
B(CreateClosure), U8(0), //
|
||||
B(Return) //
|
||||
},
|
||||
1,
|
||||
{InstanceType::SHARED_FUNCTION_INFO_TYPE}},
|
||||
{"return (function(){ })()",
|
||||
2 * kPointerSize,
|
||||
1,
|
||||
14,
|
||||
{
|
||||
B(LdaUndefined), //
|
||||
B(Star), R(1), //
|
||||
B(LdaConstant), U8(0), //
|
||||
B(CreateClosure), U8(0), //
|
||||
B(Star), R(0), //
|
||||
B(Call), R(0), R(1), U8(0), //
|
||||
B(Return) //
|
||||
},
|
||||
1,
|
||||
{InstanceType::SHARED_FUNCTION_INFO_TYPE}},
|
||||
{"return (function(x){ return x; })(1)",
|
||||
3 * kPointerSize,
|
||||
1,
|
||||
18,
|
||||
{
|
||||
B(LdaUndefined), //
|
||||
B(Star), R(1), //
|
||||
B(LdaConstant), U8(0), //
|
||||
B(CreateClosure), U8(0), //
|
||||
B(Star), R(0), //
|
||||
B(LdaSmi8), U8(1), //
|
||||
B(Star), R(2), //
|
||||
B(Call), R(0), R(1), U8(1), //
|
||||
B(Return) //
|
||||
},
|
||||
1,
|
||||
{InstanceType::SHARED_FUNCTION_INFO_TYPE}},
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < arraysize(snippets); i++) {
|
||||
Handle<BytecodeArray> bytecode_array =
|
||||
helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet);
|
||||
CheckBytecodeArrayEqual(snippets[i], bytecode_array);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace interpreter
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -1620,3 +1620,20 @@ TEST(InterpreterCallRuntime) {
|
||||
Handle<Object> return_val = callable().ToHandleChecked();
|
||||
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(55));
|
||||
}
|
||||
|
||||
|
||||
TEST(InterpreterFunctionLiteral) {
|
||||
HandleAndZoneScope handles;
|
||||
|
||||
// Test calling a function literal.
|
||||
std::string source(
|
||||
"function " + InterpreterTester::function_name() + "(a) {\n"
|
||||
" return (function(x){ return x + 2; })(a);\n"
|
||||
"}");
|
||||
InterpreterTester tester(handles.main_isolate(), source.c_str());
|
||||
auto callable = tester.GetCallable<Handle<Object>>();
|
||||
|
||||
Handle<i::Object> return_val = callable(
|
||||
Handle<Smi>(Smi::FromInt(3), handles.main_isolate())).ToHandleChecked();
|
||||
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(5));
|
||||
}
|
||||
|
@ -57,6 +57,9 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
|
||||
.StoreNamedProperty(reg, reg, 0, LanguageMode::STRICT)
|
||||
.StoreKeyedProperty(reg, reg, 0, LanguageMode::STRICT);
|
||||
|
||||
// Emit closure operations.
|
||||
builder.CreateClosure(NOT_TENURED);
|
||||
|
||||
// Call operations.
|
||||
builder.Call(reg, reg, 0);
|
||||
builder.CallRuntime(Runtime::kIsArray, reg, 1);
|
||||
|
Loading…
Reference in New Issue
Block a user