[Interpreter] TurboFan implementation of intrinsics.
Introduces a bytecode whose handler executes the equivalent of %_IsArray and %_IsJSReceiver without a runtime call. BUG=v8:4822 LOG=y Review URL: https://codereview.chromium.org/1645763003 Cr-Commit-Position: refs/heads/master@{#34983}
This commit is contained in:
parent
27338320f4
commit
d158bf14b3
2
BUILD.gn
2
BUILD.gn
@ -1133,6 +1133,8 @@ source_set("v8_base") {
|
||||
"src/interpreter/interpreter.h",
|
||||
"src/interpreter/interpreter-assembler.cc",
|
||||
"src/interpreter/interpreter-assembler.h",
|
||||
"src/interpreter/interpreter-intrinsics.cc",
|
||||
"src/interpreter/interpreter-intrinsics.h",
|
||||
"src/interpreter/source-position-table.cc",
|
||||
"src/interpreter/source-position-table.h",
|
||||
"src/isolate-inl.h",
|
||||
|
@ -231,6 +231,8 @@ namespace internal {
|
||||
V(kUnexpectedNegativeValue, "Unexpected negative value") \
|
||||
V(kUnexpectedNumberOfPreAllocatedPropertyFields, \
|
||||
"Unexpected number of pre-allocated property fields") \
|
||||
V(kUnexpectedFunctionIDForInvokeIntrinsic, \
|
||||
"Unexpected runtime function id for the InvokeIntrinsic bytecode") \
|
||||
V(kUnexpectedFPCRMode, "Unexpected FPCR mode.") \
|
||||
V(kUnexpectedSmi, "Unexpected smi value") \
|
||||
V(kUnexpectedStackDepth, "Unexpected operand stack depth in full-codegen") \
|
||||
@ -263,6 +265,8 @@ namespace internal {
|
||||
V(kWrongFunctionContext, "Wrong context passed to function") \
|
||||
V(kWrongAddressOrValuePassedToRecordWrite, \
|
||||
"Wrong address or value passed to RecordWrite") \
|
||||
V(kWrongArgumentCountForInvokeIntrinsic, \
|
||||
"Wrong number of arguments for intrinsic") \
|
||||
V(kShouldNotDirectlyEnterOsrFunction, \
|
||||
"Should not directly enter OSR-compiled function") \
|
||||
V(kYield, "Yield")
|
||||
|
@ -983,6 +983,20 @@ void BytecodeGraphBuilder::VisitCallRuntimeForPair() {
|
||||
environment()->BindRegistersToProjections(first_return, return_pair, &states);
|
||||
}
|
||||
|
||||
void BytecodeGraphBuilder::VisitInvokeIntrinsic() {
|
||||
FrameStateBeforeAndAfter states(this);
|
||||
Runtime::FunctionId functionId = static_cast<Runtime::FunctionId>(
|
||||
bytecode_iterator().GetRuntimeIdOperand(0));
|
||||
interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(1);
|
||||
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2);
|
||||
|
||||
// Create node to perform the runtime call. Turbofan will take care of the
|
||||
// lowering.
|
||||
const Operator* call = javascript()->CallRuntime(functionId, arg_count);
|
||||
Node* value = ProcessCallRuntimeArguments(call, first_arg, arg_count);
|
||||
environment()->BindAccumulator(value, &states);
|
||||
}
|
||||
|
||||
Node* BytecodeGraphBuilder::ProcessCallNewArguments(
|
||||
const Operator* call_new_op, Node* callee, Node* new_target,
|
||||
interpreter::Register first_arg, size_t arity) {
|
||||
|
@ -128,6 +128,7 @@ class BytecodeGraphBuilder {
|
||||
void BuildCastOperator(const Operator* op);
|
||||
void BuildForInPrepare();
|
||||
void BuildForInNext();
|
||||
void BuildInvokeIntrinsic();
|
||||
|
||||
// Control flow plumbing.
|
||||
void BuildJump();
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "src/interpreter/bytecode-array-builder.h"
|
||||
#include "src/compiler.h"
|
||||
#include "src/interpreter/interpreter-intrinsics.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -1026,11 +1027,13 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime(
|
||||
DCHECK_EQ(0u, arg_count);
|
||||
first_arg = Register(0);
|
||||
}
|
||||
Bytecode bytecode = IntrinsicsHelper::IsSupported(function_id)
|
||||
? Bytecode::kInvokeIntrinsic
|
||||
: Bytecode::kCallRuntime;
|
||||
OperandScale operand_scale = OperandSizesToScale(
|
||||
SizeForRegisterOperand(first_arg), SizeForUnsignedOperand(arg_count));
|
||||
OutputScaled(Bytecode::kCallRuntime, operand_scale,
|
||||
static_cast<uint16_t>(function_id), RegisterOperand(first_arg),
|
||||
UnsignedOperand(arg_count));
|
||||
OutputScaled(bytecode, operand_scale, static_cast<uint16_t>(function_id),
|
||||
RegisterOperand(first_arg), UnsignedOperand(arg_count));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -308,7 +308,8 @@ bool Bytecodes::IsCallOrNew(Bytecode bytecode) {
|
||||
// static
|
||||
bool Bytecodes::IsCallRuntime(Bytecode bytecode) {
|
||||
return bytecode == Bytecode::kCallRuntime ||
|
||||
bytecode == Bytecode::kCallRuntimeForPair;
|
||||
bytecode == Bytecode::kCallRuntimeForPair ||
|
||||
bytecode == Bytecode::kInvokeIntrinsic;
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -156,6 +156,10 @@ namespace interpreter {
|
||||
V(CallJSRuntime, OperandType::kIdx, OperandType::kReg, \
|
||||
OperandType::kRegCount) \
|
||||
\
|
||||
/* Intrinsics */ \
|
||||
V(InvokeIntrinsic, OperandType::kRuntimeId, OperandType::kMaybeReg, \
|
||||
OperandType::kRegCount) \
|
||||
\
|
||||
/* New operator */ \
|
||||
V(New, OperandType::kReg, OperandType::kMaybeReg, OperandType::kRegCount) \
|
||||
\
|
||||
|
159
src/interpreter/interpreter-intrinsics.cc
Normal file
159
src/interpreter/interpreter-intrinsics.cc
Normal file
@ -0,0 +1,159 @@
|
||||
// Copyright 2015 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/interpreter/interpreter-intrinsics.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace interpreter {
|
||||
|
||||
using compiler::Node;
|
||||
|
||||
#define __ assembler_->
|
||||
|
||||
IntrinsicsHelper::IntrinsicsHelper(InterpreterAssembler* assembler)
|
||||
: assembler_(assembler) {}
|
||||
|
||||
bool IntrinsicsHelper::IsSupported(Runtime::FunctionId function_id) {
|
||||
switch (function_id) {
|
||||
#define SUPPORTED(name, lower_case, count) case Runtime::kInline##name:
|
||||
INTRINSICS_LIST(SUPPORTED)
|
||||
return true;
|
||||
#undef SUPPORTED
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Node* IntrinsicsHelper::InvokeIntrinsic(Node* function_id, Node* context,
|
||||
Node* first_arg_reg, Node* arg_count) {
|
||||
InterpreterAssembler::Label abort(assembler_), end(assembler_);
|
||||
InterpreterAssembler::Variable result(assembler_,
|
||||
MachineRepresentation::kTagged);
|
||||
|
||||
#define MAKE_LABEL(name, lower_case, count) \
|
||||
InterpreterAssembler::Label lower_case(assembler_);
|
||||
INTRINSICS_LIST(MAKE_LABEL)
|
||||
#undef MAKE_LABEL
|
||||
|
||||
#define LABEL_POINTER(name, lower_case, count) &lower_case,
|
||||
InterpreterAssembler::Label* labels[] = {INTRINSICS_LIST(LABEL_POINTER)};
|
||||
#undef LABEL_POINTER
|
||||
|
||||
#define CASE(name, lower_case, count) \
|
||||
static_cast<int32_t>(Runtime::kInline##name),
|
||||
int32_t cases[] = {INTRINSICS_LIST(CASE)};
|
||||
#undef CASE
|
||||
|
||||
__ Switch(function_id, &abort, cases, labels, arraysize(cases));
|
||||
#define HANDLE_CASE(name, lower_case, expected_arg_count) \
|
||||
__ Bind(&lower_case); \
|
||||
if (FLAG_debug_code) { \
|
||||
AbortIfArgCountMismatch(expected_arg_count, arg_count); \
|
||||
} \
|
||||
result.Bind(name(first_arg_reg)); \
|
||||
__ Goto(&end);
|
||||
INTRINSICS_LIST(HANDLE_CASE)
|
||||
#undef HANDLE_CASE
|
||||
|
||||
__ Bind(&abort);
|
||||
__ Abort(BailoutReason::kUnexpectedFunctionIDForInvokeIntrinsic);
|
||||
result.Bind(__ UndefinedConstant());
|
||||
__ Goto(&end);
|
||||
|
||||
__ Bind(&end);
|
||||
return result.value();
|
||||
}
|
||||
|
||||
Node* IntrinsicsHelper::CompareInstanceType(Node* map, int type,
|
||||
InstanceTypeCompareMode mode) {
|
||||
InterpreterAssembler::Variable return_value(assembler_,
|
||||
MachineRepresentation::kTagged);
|
||||
Node* instance_type = __ LoadInstanceType(map);
|
||||
|
||||
InterpreterAssembler::Label if_true(assembler_), if_false(assembler_),
|
||||
end(assembler_);
|
||||
Node* condition;
|
||||
if (mode == kInstanceTypeEqual) {
|
||||
condition = __ Word32Equal(instance_type, __ Int32Constant(type));
|
||||
} else {
|
||||
DCHECK(mode == kInstanceTypeGreaterThanOrEqual);
|
||||
condition =
|
||||
__ Int32GreaterThanOrEqual(instance_type, __ Int32Constant(type));
|
||||
}
|
||||
__ Branch(condition, &if_true, &if_false);
|
||||
|
||||
__ Bind(&if_true);
|
||||
return_value.Bind(__ BooleanConstant(true));
|
||||
__ Goto(&end);
|
||||
|
||||
__ Bind(&if_false);
|
||||
return_value.Bind(__ BooleanConstant(false));
|
||||
__ Goto(&end);
|
||||
|
||||
__ Bind(&end);
|
||||
return return_value.value();
|
||||
}
|
||||
|
||||
Node* IntrinsicsHelper::IsJSReceiver(Node* input) {
|
||||
InterpreterAssembler::Variable return_value(assembler_,
|
||||
MachineRepresentation::kTagged);
|
||||
|
||||
InterpreterAssembler::Label if_smi(assembler_), if_not_smi(assembler_),
|
||||
end(assembler_);
|
||||
Node* arg = __ LoadRegister(input);
|
||||
|
||||
__ Branch(__ WordIsSmi(arg), &if_smi, &if_not_smi);
|
||||
__ Bind(&if_smi);
|
||||
return_value.Bind(__ BooleanConstant(false));
|
||||
__ Goto(&end);
|
||||
|
||||
__ Bind(&if_not_smi);
|
||||
STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
|
||||
return_value.Bind(CompareInstanceType(arg, FIRST_JS_RECEIVER_TYPE,
|
||||
kInstanceTypeGreaterThanOrEqual));
|
||||
__ Goto(&end);
|
||||
|
||||
__ Bind(&end);
|
||||
return return_value.value();
|
||||
}
|
||||
|
||||
Node* IntrinsicsHelper::IsArray(Node* input) {
|
||||
InterpreterAssembler::Variable return_value(assembler_,
|
||||
MachineRepresentation::kTagged);
|
||||
|
||||
InterpreterAssembler::Label if_smi(assembler_), if_not_smi(assembler_),
|
||||
end(assembler_);
|
||||
Node* arg = __ LoadRegister(input);
|
||||
|
||||
__ Branch(__ WordIsSmi(arg), &if_smi, &if_not_smi);
|
||||
__ Bind(&if_smi);
|
||||
return_value.Bind(__ BooleanConstant(false));
|
||||
__ Goto(&end);
|
||||
|
||||
__ Bind(&if_not_smi);
|
||||
return_value.Bind(
|
||||
CompareInstanceType(arg, JS_ARRAY_TYPE, kInstanceTypeEqual));
|
||||
__ Goto(&end);
|
||||
|
||||
__ Bind(&end);
|
||||
return return_value.value();
|
||||
}
|
||||
|
||||
void IntrinsicsHelper::AbortIfArgCountMismatch(int expected, Node* actual) {
|
||||
InterpreterAssembler::Label match(assembler_), mismatch(assembler_),
|
||||
end(assembler_);
|
||||
Node* comparison = __ Word32Equal(actual, __ Int32Constant(expected));
|
||||
__ Branch(comparison, &match, &mismatch);
|
||||
__ Bind(&mismatch);
|
||||
__ Abort(kWrongArgumentCountForInvokeIntrinsic);
|
||||
__ Goto(&end);
|
||||
__ Bind(&match);
|
||||
__ Goto(&end);
|
||||
__ Bind(&end);
|
||||
}
|
||||
|
||||
} // namespace interpreter
|
||||
} // namespace internal
|
||||
} // namespace v8
|
62
src/interpreter/interpreter-intrinsics.h
Normal file
62
src/interpreter/interpreter-intrinsics.h
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright 2015 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_INTERPRETER_INTERPRETER_INTRINSICS_H_
|
||||
#define V8_INTERPRETER_INTERPRETER_INTRINSICS_H_
|
||||
|
||||
#include "src/allocation.h"
|
||||
#include "src/base/smart-pointers.h"
|
||||
#include "src/builtins.h"
|
||||
#include "src/frames.h"
|
||||
#include "src/interpreter/bytecodes.h"
|
||||
#include "src/interpreter/interpreter-assembler.h"
|
||||
#include "src/runtime/runtime.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
namespace compiler {
|
||||
class Node;
|
||||
} // namespace compiler
|
||||
|
||||
#define INTRINSICS_LIST(V) \
|
||||
V(IsJSReceiver, is_js_receiver, 1) \
|
||||
V(IsArray, is_array, 1)
|
||||
|
||||
namespace interpreter {
|
||||
|
||||
class IntrinsicsHelper {
|
||||
public:
|
||||
explicit IntrinsicsHelper(InterpreterAssembler* assembler);
|
||||
|
||||
compiler::Node* InvokeIntrinsic(compiler::Node* function_id,
|
||||
compiler::Node* context,
|
||||
compiler::Node* first_arg_reg,
|
||||
compiler::Node* arg_count);
|
||||
|
||||
static bool IsSupported(Runtime::FunctionId function_id);
|
||||
|
||||
private:
|
||||
enum InstanceTypeCompareMode {
|
||||
kInstanceTypeEqual,
|
||||
kInstanceTypeGreaterThanOrEqual
|
||||
};
|
||||
compiler::Node* CompareInstanceType(compiler::Node* map, int type,
|
||||
InstanceTypeCompareMode mode);
|
||||
void AbortIfArgCountMismatch(int expected, compiler::Node* actual);
|
||||
InterpreterAssembler* assembler_;
|
||||
|
||||
#define DECLARE_INTRINSIC_HELPER(name, lower_case, count) \
|
||||
compiler::Node* name(compiler::Node* input);
|
||||
INTRINSICS_LIST(DECLARE_INTRINSIC_HELPER)
|
||||
#undef DECLARE_INTRINSIC_HELPER
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(IntrinsicsHelper);
|
||||
};
|
||||
|
||||
} // namespace interpreter
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif
|
@ -11,6 +11,7 @@
|
||||
#include "src/interpreter/bytecode-generator.h"
|
||||
#include "src/interpreter/bytecodes.h"
|
||||
#include "src/interpreter/interpreter-assembler.h"
|
||||
#include "src/interpreter/interpreter-intrinsics.h"
|
||||
#include "src/log.h"
|
||||
#include "src/zone.h"
|
||||
|
||||
@ -894,6 +895,23 @@ void Interpreter::DoCallRuntime(InterpreterAssembler* assembler) {
|
||||
DoCallRuntimeCommon(assembler);
|
||||
}
|
||||
|
||||
// InvokeIntrinsic <function_id> <first_arg> <arg_count>
|
||||
//
|
||||
// Implements the semantic equivalent of calling the runtime function
|
||||
// |function_id| with the first argument in |first_arg| and |arg_count|
|
||||
// arguments in subsequent registers.
|
||||
void Interpreter::DoInvokeIntrinsic(InterpreterAssembler* assembler) {
|
||||
Node* function_id = __ BytecodeOperandRuntimeId(0);
|
||||
Node* first_arg_reg = __ BytecodeOperandReg(1);
|
||||
Node* arg_count = __ BytecodeOperandCount(2);
|
||||
Node* context = __ GetContext();
|
||||
IntrinsicsHelper helper(assembler);
|
||||
Node* result =
|
||||
helper.InvokeIntrinsic(function_id, context, first_arg_reg, arg_count);
|
||||
__ SetAccumulator(result);
|
||||
__ Dispatch();
|
||||
}
|
||||
|
||||
void Interpreter::DoCallRuntimeForPairCommon(InterpreterAssembler* assembler) {
|
||||
// Call the runtime function.
|
||||
Node* function_id = __ BytecodeOperandRuntimeId(0);
|
||||
|
@ -89,8 +89,10 @@
|
||||
'cctest.cc',
|
||||
'expression-type-collector.cc',
|
||||
'expression-type-collector.h',
|
||||
'interpreter/interpreter-tester.cc',
|
||||
'interpreter/test-bytecode-generator.cc',
|
||||
'interpreter/test-interpreter.cc',
|
||||
'interpreter/test-interpreter-intrinsics.cc',
|
||||
'interpreter/bytecode-expectations-printer.cc',
|
||||
'interpreter/bytecode-expectations-printer.h',
|
||||
'gay-fixed.cc',
|
||||
|
@ -659,6 +659,28 @@ TEST(BytecodeGraphBuilderCallRuntime) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BytecodeGraphBuilderInvokeIntrinsic) {
|
||||
HandleAndZoneScope scope;
|
||||
Isolate* isolate = scope.main_isolate();
|
||||
Zone* zone = scope.main_zone();
|
||||
Factory* factory = isolate->factory();
|
||||
|
||||
ExpectedSnippet<1> snippets[] = {
|
||||
{"function f(arg0) { return %_IsJSReceiver(arg0); }\nf()",
|
||||
{factory->false_value(), factory->NewNumberFromInt(1)}},
|
||||
{"function f(arg0) { return %_IsArray(arg0) }\nf(undefined)",
|
||||
{factory->true_value(), BytecodeGraphTester::NewObject("[1, 2, 3]")}},
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < arraysize(snippets); i++) {
|
||||
BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet);
|
||||
auto callable = tester.GetCallable<Handle<Object>>();
|
||||
Handle<Object> return_value =
|
||||
callable(snippets[i].parameter(0)).ToHandleChecked();
|
||||
CHECK(return_value->SameValue(*snippets[i].return_value()));
|
||||
}
|
||||
}
|
||||
|
||||
void TestBytecodeGraphBuilderGlobals(size_t shard) {
|
||||
HandleAndZoneScope scope;
|
||||
Isolate* isolate = scope.main_isolate();
|
||||
|
@ -36,7 +36,7 @@ bytecodes: [
|
||||
B(Call), R(14), R(15), U8(1), U8(5),
|
||||
B(Star), R(2),
|
||||
B(Star), R(13),
|
||||
B(CallRuntime), U16(Runtime::k_IsJSReceiver), R(13), U8(1),
|
||||
B(InvokeIntrinsic), U16(Runtime::k_IsJSReceiver), R(13), U8(1),
|
||||
B(LogicalNot),
|
||||
B(JumpIfFalse), U8(11),
|
||||
B(Ldar), R(2),
|
||||
@ -151,7 +151,7 @@ bytecodes: [
|
||||
B(CallRuntime), U16(Runtime::k_Call), R(12), U8(2),
|
||||
B(Star), R(6),
|
||||
B(Star), R(12),
|
||||
B(CallRuntime), U16(Runtime::k_IsJSReceiver), R(12), U8(1),
|
||||
B(InvokeIntrinsic), U16(Runtime::k_IsJSReceiver), R(12), U8(1),
|
||||
B(JumpIfToBooleanFalse), U8(4),
|
||||
B(Jump), U8(11),
|
||||
B(Ldar), R(6),
|
||||
@ -217,7 +217,7 @@ bytecodes: [
|
||||
B(Call), R(15), R(16), U8(1), U8(5),
|
||||
B(Star), R(2),
|
||||
B(Star), R(14),
|
||||
B(CallRuntime), U16(Runtime::k_IsJSReceiver), R(14), U8(1),
|
||||
B(InvokeIntrinsic), U16(Runtime::k_IsJSReceiver), R(14), U8(1),
|
||||
B(LogicalNot),
|
||||
B(JumpIfFalse), U8(11),
|
||||
B(Ldar), R(2),
|
||||
@ -334,7 +334,7 @@ bytecodes: [
|
||||
B(CallRuntime), U16(Runtime::k_Call), R(13), U8(2),
|
||||
B(Star), R(6),
|
||||
B(Star), R(13),
|
||||
B(CallRuntime), U16(Runtime::k_IsJSReceiver), R(13), U8(1),
|
||||
B(InvokeIntrinsic), U16(Runtime::k_IsJSReceiver), R(13), U8(1),
|
||||
B(JumpIfToBooleanFalse), U8(4),
|
||||
B(Jump), U8(11),
|
||||
B(Ldar), R(6),
|
||||
@ -405,7 +405,7 @@ bytecodes: [
|
||||
B(Call), R(14), R(15), U8(1), U8(5),
|
||||
B(Star), R(2),
|
||||
B(Star), R(13),
|
||||
B(CallRuntime), U16(Runtime::k_IsJSReceiver), R(13), U8(1),
|
||||
B(InvokeIntrinsic), U16(Runtime::k_IsJSReceiver), R(13), U8(1),
|
||||
B(LogicalNot),
|
||||
B(JumpIfFalse), U8(11),
|
||||
B(Ldar), R(2),
|
||||
@ -531,7 +531,7 @@ bytecodes: [
|
||||
B(CallRuntime), U16(Runtime::k_Call), R(12), U8(2),
|
||||
B(Star), R(6),
|
||||
B(Star), R(12),
|
||||
B(CallRuntime), U16(Runtime::k_IsJSReceiver), R(12), U8(1),
|
||||
B(InvokeIntrinsic), U16(Runtime::k_IsJSReceiver), R(12), U8(1),
|
||||
B(JumpIfToBooleanFalse), U8(4),
|
||||
B(Jump), U8(11),
|
||||
B(Ldar), R(6),
|
||||
@ -598,7 +598,7 @@ bytecodes: [
|
||||
B(Call), R(13), R(14), U8(1), U8(5),
|
||||
B(Star), R(1),
|
||||
B(Star), R(12),
|
||||
B(CallRuntime), U16(Runtime::k_IsJSReceiver), R(12), U8(1),
|
||||
B(InvokeIntrinsic), U16(Runtime::k_IsJSReceiver), R(12), U8(1),
|
||||
B(LogicalNot),
|
||||
B(JumpIfFalse), U8(11),
|
||||
B(Ldar), R(1),
|
||||
@ -718,7 +718,7 @@ bytecodes: [
|
||||
B(CallRuntime), U16(Runtime::k_Call), R(11), U8(2),
|
||||
B(Star), R(5),
|
||||
B(Star), R(11),
|
||||
B(CallRuntime), U16(Runtime::k_IsJSReceiver), R(11), U8(1),
|
||||
B(InvokeIntrinsic), U16(Runtime::k_IsJSReceiver), R(11), U8(1),
|
||||
B(JumpIfToBooleanFalse), U8(4),
|
||||
B(Jump), U8(11),
|
||||
B(Ldar), R(5),
|
||||
|
79
test/cctest/interpreter/interpreter-tester.cc
Normal file
79
test/cctest/interpreter/interpreter-tester.cc
Normal file
@ -0,0 +1,79 @@
|
||||
// Copyright 2015 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "test/cctest/interpreter/interpreter-tester.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace interpreter {
|
||||
|
||||
MaybeHandle<Object> CallInterpreter(Isolate* isolate,
|
||||
Handle<JSFunction> function) {
|
||||
return Execution::Call(isolate, function,
|
||||
isolate->factory()->undefined_value(), 0, nullptr);
|
||||
}
|
||||
|
||||
InterpreterTester::InterpreterTester(
|
||||
Isolate* isolate, const char* source, MaybeHandle<BytecodeArray> bytecode,
|
||||
MaybeHandle<TypeFeedbackVector> feedback_vector, const char* filter)
|
||||
: isolate_(isolate),
|
||||
source_(source),
|
||||
bytecode_(bytecode),
|
||||
feedback_vector_(feedback_vector) {
|
||||
i::FLAG_ignition = true;
|
||||
i::FLAG_always_opt = false;
|
||||
// Set ignition filter flag via SetFlagsFromString to avoid double-free
|
||||
// (or potential leak with StrDup() based on ownership confusion).
|
||||
ScopedVector<char> ignition_filter(64);
|
||||
SNPrintF(ignition_filter, "--ignition-filter=%s", filter);
|
||||
FlagList::SetFlagsFromString(ignition_filter.start(),
|
||||
ignition_filter.length());
|
||||
// Ensure handler table is generated.
|
||||
isolate->interpreter()->Initialize();
|
||||
}
|
||||
|
||||
InterpreterTester::InterpreterTester(
|
||||
Isolate* isolate, Handle<BytecodeArray> bytecode,
|
||||
MaybeHandle<TypeFeedbackVector> feedback_vector, const char* filter)
|
||||
: InterpreterTester(isolate, nullptr, bytecode, feedback_vector, filter) {}
|
||||
|
||||
InterpreterTester::InterpreterTester(Isolate* isolate, const char* source,
|
||||
const char* filter)
|
||||
: InterpreterTester(isolate, source, MaybeHandle<BytecodeArray>(),
|
||||
MaybeHandle<TypeFeedbackVector>(), filter) {}
|
||||
|
||||
InterpreterTester::~InterpreterTester() {}
|
||||
|
||||
Local<Message> InterpreterTester::CheckThrowsReturnMessage() {
|
||||
TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate_));
|
||||
auto callable = GetCallable<>();
|
||||
MaybeHandle<Object> no_result = callable();
|
||||
CHECK(isolate_->has_pending_exception());
|
||||
CHECK(try_catch.HasCaught());
|
||||
CHECK(no_result.is_null());
|
||||
isolate_->OptionalRescheduleException(true);
|
||||
CHECK(!try_catch.Message().IsEmpty());
|
||||
return try_catch.Message();
|
||||
}
|
||||
|
||||
Handle<Object> InterpreterTester::NewObject(const char* script) {
|
||||
return v8::Utils::OpenHandle(*CompileRun(script));
|
||||
}
|
||||
|
||||
Handle<String> InterpreterTester::GetName(Isolate* isolate, const char* name) {
|
||||
Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(name);
|
||||
return isolate->factory()->string_table()->LookupString(isolate, result);
|
||||
}
|
||||
|
||||
std::string InterpreterTester::SourceForBody(const char* body) {
|
||||
return "function " + function_name() + "() {\n" + std::string(body) + "\n}";
|
||||
}
|
||||
|
||||
std::string InterpreterTester::function_name() {
|
||||
return std::string(kFunctionName);
|
||||
}
|
||||
|
||||
} // namespace interpreter
|
||||
} // namespace internal
|
||||
} // namespace v8
|
128
test/cctest/interpreter/interpreter-tester.h
Normal file
128
test/cctest/interpreter/interpreter-tester.h
Normal file
@ -0,0 +1,128 @@
|
||||
// Copyright 2015 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/v8.h"
|
||||
|
||||
#include "src/execution.h"
|
||||
#include "src/handles.h"
|
||||
#include "src/interpreter/bytecode-array-builder.h"
|
||||
#include "src/interpreter/interpreter.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/test-feedback-vector.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace interpreter {
|
||||
|
||||
MaybeHandle<Object> CallInterpreter(Isolate* isolate,
|
||||
Handle<JSFunction> function);
|
||||
template <class... A>
|
||||
static MaybeHandle<Object> CallInterpreter(Isolate* isolate,
|
||||
Handle<JSFunction> function,
|
||||
A... args) {
|
||||
Handle<Object> argv[] = {args...};
|
||||
return Execution::Call(isolate, function,
|
||||
isolate->factory()->undefined_value(), sizeof...(args),
|
||||
argv);
|
||||
}
|
||||
|
||||
template <class... A>
|
||||
class InterpreterCallable {
|
||||
public:
|
||||
InterpreterCallable(Isolate* isolate, Handle<JSFunction> function)
|
||||
: isolate_(isolate), function_(function) {}
|
||||
virtual ~InterpreterCallable() {}
|
||||
|
||||
MaybeHandle<Object> operator()(A... args) {
|
||||
return CallInterpreter(isolate_, function_, args...);
|
||||
}
|
||||
|
||||
private:
|
||||
Isolate* isolate_;
|
||||
Handle<JSFunction> function_;
|
||||
};
|
||||
|
||||
namespace {
|
||||
const char kFunctionName[] = "f";
|
||||
} // namespace
|
||||
|
||||
class InterpreterTester {
|
||||
public:
|
||||
InterpreterTester(Isolate* isolate, const char* source,
|
||||
MaybeHandle<BytecodeArray> bytecode,
|
||||
MaybeHandle<TypeFeedbackVector> feedback_vector,
|
||||
const char* filter);
|
||||
|
||||
InterpreterTester(Isolate* isolate, Handle<BytecodeArray> bytecode,
|
||||
MaybeHandle<TypeFeedbackVector> feedback_vector =
|
||||
MaybeHandle<TypeFeedbackVector>(),
|
||||
const char* filter = kFunctionName);
|
||||
|
||||
InterpreterTester(Isolate* isolate, const char* source,
|
||||
const char* filter = kFunctionName);
|
||||
|
||||
virtual ~InterpreterTester();
|
||||
|
||||
template <class... A>
|
||||
InterpreterCallable<A...> GetCallable() {
|
||||
return InterpreterCallable<A...>(isolate_, GetBytecodeFunction<A...>());
|
||||
}
|
||||
|
||||
Local<Message> CheckThrowsReturnMessage();
|
||||
|
||||
static Handle<Object> NewObject(const char* script);
|
||||
|
||||
static Handle<String> GetName(Isolate* isolate, const char* name);
|
||||
|
||||
static std::string SourceForBody(const char* body);
|
||||
|
||||
static std::string function_name();
|
||||
|
||||
private:
|
||||
Isolate* isolate_;
|
||||
const char* source_;
|
||||
MaybeHandle<BytecodeArray> bytecode_;
|
||||
MaybeHandle<TypeFeedbackVector> feedback_vector_;
|
||||
|
||||
template <class... A>
|
||||
Handle<JSFunction> GetBytecodeFunction() {
|
||||
Handle<JSFunction> function;
|
||||
if (source_) {
|
||||
CompileRun(source_);
|
||||
v8::Local<v8::Context> context =
|
||||
v8::Isolate::GetCurrent()->GetCurrentContext();
|
||||
Local<Function> api_function =
|
||||
Local<Function>::Cast(CcTest::global()
|
||||
->Get(context, v8_str(kFunctionName))
|
||||
.ToLocalChecked());
|
||||
function = Handle<JSFunction>::cast(v8::Utils::OpenHandle(*api_function));
|
||||
} else {
|
||||
int arg_count = sizeof...(A);
|
||||
std::string source("(function " + function_name() + "(");
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
source += i == 0 ? "a" : ", a";
|
||||
}
|
||||
source += "){})";
|
||||
function = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
|
||||
*v8::Local<v8::Function>::Cast(CompileRun(source.c_str()))));
|
||||
function->ReplaceCode(
|
||||
*isolate_->builtins()->InterpreterEntryTrampoline());
|
||||
}
|
||||
|
||||
if (!bytecode_.is_null()) {
|
||||
function->shared()->set_function_data(*bytecode_.ToHandleChecked());
|
||||
}
|
||||
if (!feedback_vector_.is_null()) {
|
||||
function->shared()->set_feedback_vector(
|
||||
*feedback_vector_.ToHandleChecked());
|
||||
}
|
||||
return function;
|
||||
}
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(InterpreterTester);
|
||||
};
|
||||
|
||||
} // namespace interpreter
|
||||
} // namespace internal
|
||||
} // namespace v8
|
96
test/cctest/interpreter/test-interpreter-intrinsics.cc
Normal file
96
test/cctest/interpreter/test-interpreter-intrinsics.cc
Normal file
@ -0,0 +1,96 @@
|
||||
// Copyright 2015 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/v8.h"
|
||||
|
||||
#include "src/interpreter/interpreter-intrinsics.h"
|
||||
#include "test/cctest/interpreter/interpreter-tester.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace interpreter {
|
||||
|
||||
namespace {
|
||||
|
||||
class InvokeIntrinsicHelper {
|
||||
public:
|
||||
InvokeIntrinsicHelper(Isolate* isolate, Zone* zone,
|
||||
Runtime::FunctionId function_id)
|
||||
: isolate_(isolate),
|
||||
zone_(zone),
|
||||
factory_(isolate->factory()),
|
||||
function_id_(function_id) {}
|
||||
|
||||
template <class... A>
|
||||
Handle<Object> Invoke(A... args) {
|
||||
CHECK(IntrinsicsHelper::IsSupported(function_id_));
|
||||
BytecodeArrayBuilder builder(isolate_, zone_, sizeof...(args), 0, 0);
|
||||
builder.CallRuntime(function_id_, builder.Parameter(0), sizeof...(args))
|
||||
.Return();
|
||||
InterpreterTester tester(isolate_, builder.ToBytecodeArray());
|
||||
auto callable = tester.GetCallable<Handle<Object>>();
|
||||
return callable(args...).ToHandleChecked();
|
||||
}
|
||||
|
||||
Handle<Object> NewObject(const char* script) {
|
||||
return v8::Utils::OpenHandle(*CompileRun(script));
|
||||
}
|
||||
|
||||
Handle<Object> Undefined() { return factory_->undefined_value(); }
|
||||
Handle<Object> Null() { return factory_->null_value(); }
|
||||
|
||||
private:
|
||||
Isolate* isolate_;
|
||||
Zone* zone_;
|
||||
Factory* factory_;
|
||||
Runtime::FunctionId function_id_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(IsJSReceiver) {
|
||||
HandleAndZoneScope handles;
|
||||
|
||||
InvokeIntrinsicHelper helper(handles.main_isolate(), handles.main_zone(),
|
||||
Runtime::kInlineIsJSReceiver);
|
||||
Factory* factory = handles.main_isolate()->factory();
|
||||
|
||||
CHECK_EQ(*factory->true_value(),
|
||||
*helper.Invoke(helper.NewObject("new Date()")));
|
||||
CHECK_EQ(*factory->true_value(),
|
||||
*helper.Invoke(helper.NewObject("(function() {})")));
|
||||
CHECK_EQ(*factory->true_value(), *helper.Invoke(helper.NewObject("([1])")));
|
||||
CHECK_EQ(*factory->true_value(), *helper.Invoke(helper.NewObject("({})")));
|
||||
CHECK_EQ(*factory->true_value(), *helper.Invoke(helper.NewObject("(/x/)")));
|
||||
CHECK_EQ(*factory->false_value(), *helper.Invoke(helper.Undefined()));
|
||||
CHECK_EQ(*factory->false_value(), *helper.Invoke(helper.Null()));
|
||||
CHECK_EQ(*factory->false_value(),
|
||||
*helper.Invoke(helper.NewObject("'string'")));
|
||||
CHECK_EQ(*factory->false_value(), *helper.Invoke(helper.NewObject("42")));
|
||||
}
|
||||
|
||||
TEST(IsArray) {
|
||||
HandleAndZoneScope handles;
|
||||
|
||||
InvokeIntrinsicHelper helper(handles.main_isolate(), handles.main_zone(),
|
||||
Runtime::kInlineIsArray);
|
||||
Factory* factory = handles.main_isolate()->factory();
|
||||
|
||||
CHECK_EQ(*factory->false_value(),
|
||||
*helper.Invoke(helper.NewObject("new Date()")));
|
||||
CHECK_EQ(*factory->false_value(),
|
||||
*helper.Invoke(helper.NewObject("(function() {})")));
|
||||
CHECK_EQ(*factory->true_value(), *helper.Invoke(helper.NewObject("([1])")));
|
||||
CHECK_EQ(*factory->false_value(), *helper.Invoke(helper.NewObject("({})")));
|
||||
CHECK_EQ(*factory->false_value(), *helper.Invoke(helper.NewObject("(/x/)")));
|
||||
CHECK_EQ(*factory->false_value(), *helper.Invoke(helper.Undefined()));
|
||||
CHECK_EQ(*factory->false_value(), *helper.Invoke(helper.Null()));
|
||||
CHECK_EQ(*factory->false_value(),
|
||||
*helper.Invoke(helper.NewObject("'string'")));
|
||||
CHECK_EQ(*factory->false_value(), *helper.Invoke(helper.NewObject("42")));
|
||||
}
|
||||
|
||||
} // namespace interpreter
|
||||
} // namespace internal
|
||||
} // namespace v8
|
@ -9,6 +9,7 @@
|
||||
#include "src/interpreter/bytecode-array-builder.h"
|
||||
#include "src/interpreter/interpreter.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/interpreter/interpreter-tester.h"
|
||||
#include "test/cctest/test-feedback-vector.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -16,160 +17,6 @@ namespace internal {
|
||||
namespace interpreter {
|
||||
|
||||
|
||||
static MaybeHandle<Object> CallInterpreter(Isolate* isolate,
|
||||
Handle<JSFunction> function) {
|
||||
return Execution::Call(isolate, function,
|
||||
isolate->factory()->undefined_value(), 0, nullptr);
|
||||
}
|
||||
|
||||
|
||||
template <class... A>
|
||||
static MaybeHandle<Object> CallInterpreter(Isolate* isolate,
|
||||
Handle<JSFunction> function,
|
||||
A... args) {
|
||||
Handle<Object> argv[] = { args... };
|
||||
return Execution::Call(isolate, function,
|
||||
isolate->factory()->undefined_value(), sizeof...(args),
|
||||
argv);
|
||||
}
|
||||
|
||||
|
||||
template <class... A>
|
||||
class InterpreterCallable {
|
||||
public:
|
||||
InterpreterCallable(Isolate* isolate, Handle<JSFunction> function)
|
||||
: isolate_(isolate), function_(function) {}
|
||||
virtual ~InterpreterCallable() {}
|
||||
|
||||
MaybeHandle<Object> operator()(A... args) {
|
||||
return CallInterpreter(isolate_, function_, args...);
|
||||
}
|
||||
|
||||
private:
|
||||
Isolate* isolate_;
|
||||
Handle<JSFunction> function_;
|
||||
};
|
||||
|
||||
|
||||
static const char* kFunctionName = "f";
|
||||
|
||||
|
||||
class InterpreterTester {
|
||||
public:
|
||||
InterpreterTester(Isolate* isolate, const char* source,
|
||||
MaybeHandle<BytecodeArray> bytecode,
|
||||
MaybeHandle<TypeFeedbackVector> feedback_vector,
|
||||
const char* filter)
|
||||
: isolate_(isolate),
|
||||
source_(source),
|
||||
bytecode_(bytecode),
|
||||
feedback_vector_(feedback_vector) {
|
||||
i::FLAG_ignition = true;
|
||||
i::FLAG_always_opt = false;
|
||||
// Set ignition filter flag via SetFlagsFromString to avoid double-free
|
||||
// (or potential leak with StrDup() based on ownership confusion).
|
||||
ScopedVector<char> ignition_filter(64);
|
||||
SNPrintF(ignition_filter, "--ignition-filter=%s", filter);
|
||||
FlagList::SetFlagsFromString(ignition_filter.start(),
|
||||
ignition_filter.length());
|
||||
// Ensure handler table is generated.
|
||||
isolate->interpreter()->Initialize();
|
||||
}
|
||||
|
||||
InterpreterTester(Isolate* isolate, Handle<BytecodeArray> bytecode,
|
||||
MaybeHandle<TypeFeedbackVector> feedback_vector =
|
||||
MaybeHandle<TypeFeedbackVector>(),
|
||||
const char* filter = kFunctionName)
|
||||
: InterpreterTester(isolate, nullptr, bytecode, feedback_vector, filter) {
|
||||
}
|
||||
|
||||
|
||||
InterpreterTester(Isolate* isolate, const char* source,
|
||||
const char* filter = kFunctionName)
|
||||
: InterpreterTester(isolate, source, MaybeHandle<BytecodeArray>(),
|
||||
MaybeHandle<TypeFeedbackVector>(), filter) {}
|
||||
|
||||
virtual ~InterpreterTester() {}
|
||||
|
||||
template <class... A>
|
||||
InterpreterCallable<A...> GetCallable() {
|
||||
return InterpreterCallable<A...>(isolate_, GetBytecodeFunction<A...>());
|
||||
}
|
||||
|
||||
Local<Message> CheckThrowsReturnMessage() {
|
||||
TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate_));
|
||||
auto callable = GetCallable<>();
|
||||
MaybeHandle<Object> no_result = callable();
|
||||
CHECK(isolate_->has_pending_exception());
|
||||
CHECK(try_catch.HasCaught());
|
||||
CHECK(no_result.is_null());
|
||||
isolate_->OptionalRescheduleException(true);
|
||||
CHECK(!try_catch.Message().IsEmpty());
|
||||
return try_catch.Message();
|
||||
}
|
||||
|
||||
static Handle<Object> NewObject(const char* script) {
|
||||
return v8::Utils::OpenHandle(*CompileRun(script));
|
||||
}
|
||||
|
||||
static Handle<String> GetName(Isolate* isolate, const char* name) {
|
||||
Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(name);
|
||||
return isolate->factory()->string_table()->LookupString(isolate, result);
|
||||
}
|
||||
|
||||
static std::string SourceForBody(const char* body) {
|
||||
return "function " + function_name() + "() {\n" + std::string(body) + "\n}";
|
||||
}
|
||||
|
||||
static std::string function_name() {
|
||||
return std::string(kFunctionName);
|
||||
}
|
||||
|
||||
private:
|
||||
Isolate* isolate_;
|
||||
const char* source_;
|
||||
MaybeHandle<BytecodeArray> bytecode_;
|
||||
MaybeHandle<TypeFeedbackVector> feedback_vector_;
|
||||
|
||||
template <class... A>
|
||||
Handle<JSFunction> GetBytecodeFunction() {
|
||||
Handle<JSFunction> function;
|
||||
if (source_) {
|
||||
CompileRun(source_);
|
||||
v8::Local<v8::Context> context =
|
||||
v8::Isolate::GetCurrent()->GetCurrentContext();
|
||||
Local<Function> api_function =
|
||||
Local<Function>::Cast(CcTest::global()
|
||||
->Get(context, v8_str(kFunctionName))
|
||||
.ToLocalChecked());
|
||||
function = Handle<JSFunction>::cast(v8::Utils::OpenHandle(*api_function));
|
||||
} else {
|
||||
int arg_count = sizeof...(A);
|
||||
std::string source("(function " + function_name() + "(");
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
source += i == 0 ? "a" : ", a";
|
||||
}
|
||||
source += "){})";
|
||||
function = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
|
||||
*v8::Local<v8::Function>::Cast(CompileRun(source.c_str()))));
|
||||
function->ReplaceCode(
|
||||
*isolate_->builtins()->InterpreterEntryTrampoline());
|
||||
}
|
||||
|
||||
if (!bytecode_.is_null()) {
|
||||
function->shared()->set_function_data(*bytecode_.ToHandleChecked());
|
||||
}
|
||||
if (!feedback_vector_.is_null()) {
|
||||
function->shared()->set_feedback_vector(
|
||||
*feedback_vector_.ToHandleChecked());
|
||||
}
|
||||
return function;
|
||||
}
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(InterpreterTester);
|
||||
};
|
||||
|
||||
|
||||
TEST(InterpreterReturn) {
|
||||
HandleAndZoneScope handles;
|
||||
Handle<Object> undefined_value =
|
||||
@ -1639,6 +1486,24 @@ TEST(InterpreterCallRuntime) {
|
||||
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(55));
|
||||
}
|
||||
|
||||
TEST(InterpreterInvokeIntrinsic) {
|
||||
HandleAndZoneScope handles;
|
||||
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
|
||||
0, 2);
|
||||
builder.LoadLiteral(Smi::FromInt(15))
|
||||
.StoreAccumulatorInRegister(Register(0))
|
||||
.CallRuntime(Runtime::kInlineIsArray, Register(0), 1)
|
||||
.Return();
|
||||
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
||||
|
||||
InterpreterTester tester(handles.main_isolate(), bytecode_array);
|
||||
auto callable = tester.GetCallable<>();
|
||||
|
||||
Handle<Object> return_val = callable().ToHandleChecked();
|
||||
CHECK(return_val->IsBoolean());
|
||||
CHECK_EQ(return_val->BooleanValue(), false);
|
||||
}
|
||||
|
||||
TEST(InterpreterFunctionLiteral) {
|
||||
HandleAndZoneScope handles;
|
||||
|
@ -289,6 +289,10 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
|
||||
.BinaryOperation(Token::Value::ADD, reg)
|
||||
.JumpIfFalse(&start);
|
||||
|
||||
// Intrinsics handled by the interpreter.
|
||||
builder.CallRuntime(Runtime::kInlineIsArray, reg, 1)
|
||||
.CallRuntime(Runtime::kInlineIsArray, wide, 1);
|
||||
|
||||
builder.Debugger();
|
||||
for (size_t i = 0; i < arraysize(end); i++) {
|
||||
builder.Bind(&end[i]);
|
||||
|
@ -960,6 +960,8 @@
|
||||
'../../src/interpreter/interpreter.h',
|
||||
'../../src/interpreter/interpreter-assembler.cc',
|
||||
'../../src/interpreter/interpreter-assembler.h',
|
||||
'../../src/interpreter/interpreter-intrinsics.cc',
|
||||
'../../src/interpreter/interpreter-intrinsics.h',
|
||||
'../../src/interpreter/source-position-table.cc',
|
||||
'../../src/interpreter/source-position-table.h',
|
||||
'../../src/isolate-inl.h',
|
||||
|
Loading…
Reference in New Issue
Block a user