Commit 935340a4 authored by klaasb's avatar klaasb Committed by Commit bot

[interpreter] VisitForTest for bytecode generator

Adds TestResultScope and uses it to directly jump/fall through to the
correct branch in expressions used as branch conditions.
Should enable nicer TurboFan-graphs for easier control-flow
transformations in the future.

BUG=v8:4280
LOG=n

Review-Url: https://codereview.chromium.org/2242463002
Cr-Commit-Position: refs/heads/master@{#38634}
parent 160d0a18
...@@ -1381,6 +1381,7 @@ v8_source_set("v8_base") { ...@@ -1381,6 +1381,7 @@ v8_source_set("v8_base") {
"src/interpreter/bytecode-flags.h", "src/interpreter/bytecode-flags.h",
"src/interpreter/bytecode-generator.cc", "src/interpreter/bytecode-generator.cc",
"src/interpreter/bytecode-generator.h", "src/interpreter/bytecode-generator.h",
"src/interpreter/bytecode-label.cc",
"src/interpreter/bytecode-label.h", "src/interpreter/bytecode-label.h",
"src/interpreter/bytecode-peephole-optimizer.cc", "src/interpreter/bytecode-peephole-optimizer.cc",
"src/interpreter/bytecode-peephole-optimizer.h", "src/interpreter/bytecode-peephole-optimizer.h",
......
This diff is collapsed.
...@@ -48,6 +48,9 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { ...@@ -48,6 +48,9 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
class GlobalDeclarationsBuilder; class GlobalDeclarationsBuilder;
class RegisterResultScope; class RegisterResultScope;
class RegisterAllocationScope; class RegisterAllocationScope;
class TestResultScope;
enum class TestFallthrough { kThen, kElse, kNone };
void GenerateBytecode(); void GenerateBytecode();
void GenerateBytecodeBody(); void GenerateBytecodeBody();
...@@ -162,6 +165,8 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { ...@@ -162,6 +165,8 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
MUST_USE_RESULT Register VisitForRegisterValue(Expression* expr); MUST_USE_RESULT Register VisitForRegisterValue(Expression* expr);
void VisitForRegisterValue(Expression* expr, Register destination); void VisitForRegisterValue(Expression* expr, Register destination);
void VisitForEffect(Expression* expr); void VisitForEffect(Expression* expr);
void VisitForTest(Expression* expr, BytecodeLabels* then_labels,
BytecodeLabels* else_labels, TestFallthrough fallthrough);
// Methods for tracking and remapping register. // Methods for tracking and remapping register.
void RecordStoreToRegister(Register reg); void RecordStoreToRegister(Register reg);
......
// Copyright 2016 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/bytecode-label.h"
#include "src/interpreter/bytecode-array-builder.h"
namespace v8 {
namespace internal {
namespace interpreter {
BytecodeLabel* BytecodeLabels::New() {
labels_.push_back(BytecodeLabel());
return &labels_.back();
}
void BytecodeLabels::Bind(BytecodeArrayBuilder* builder) {
for (auto label : labels_) {
builder->Bind(&label);
}
}
} // namespace interpreter
} // namespace internal
} // namespace v8
...@@ -5,10 +5,14 @@ ...@@ -5,10 +5,14 @@
#ifndef V8_INTERPRETER_BYTECODE_LABEL_H_ #ifndef V8_INTERPRETER_BYTECODE_LABEL_H_
#define V8_INTERPRETER_BYTECODE_LABEL_H_ #define V8_INTERPRETER_BYTECODE_LABEL_H_
#include "src/zone-containers.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
namespace interpreter { namespace interpreter {
class BytecodeArrayBuilder;
// A label representing a branch target in a bytecode array. When a // A label representing a branch target in a bytecode array. When a
// label is bound, it represents a known position in the bytecode // label is bound, it represents a known position in the bytecode
// array. For labels that are forward references there can be at most // array. For labels that are forward references there can be at most
...@@ -49,6 +53,21 @@ class BytecodeLabel final { ...@@ -49,6 +53,21 @@ class BytecodeLabel final {
friend class BytecodeArrayWriter; friend class BytecodeArrayWriter;
}; };
// Class representing a branch target of multiple jumps.
class BytecodeLabels {
public:
explicit BytecodeLabels(Zone* zone) : labels_(zone) {}
BytecodeLabel* New();
void Bind(BytecodeArrayBuilder* builder);
private:
ZoneVector<BytecodeLabel> labels_;
DISALLOW_COPY_AND_ASSIGN(BytecodeLabels);
};
} // namespace interpreter } // namespace interpreter
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -985,6 +985,7 @@ ...@@ -985,6 +985,7 @@
'interpreter/bytecode-flags.h', 'interpreter/bytecode-flags.h',
'interpreter/bytecode-generator.cc', 'interpreter/bytecode-generator.cc',
'interpreter/bytecode-generator.h', 'interpreter/bytecode-generator.h',
'interpreter/bytecode-label.cc',
'interpreter/bytecode-label.h', 'interpreter/bytecode-label.h',
'interpreter/bytecode-peephole-optimizer.cc', 'interpreter/bytecode-peephole-optimizer.cc',
'interpreter/bytecode-peephole-optimizer.h', 'interpreter/bytecode-peephole-optimizer.h',
......
...@@ -18,10 +18,10 @@ bytecodes: [ ...@@ -18,10 +18,10 @@ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), U8(1), /* 42 S> */ B(LdaSmi), U8(1),
B(Star), R(0), B(Star), R(0),
/* 45 S> */ B(JumpIfToBooleanTrue), U8(5), /* 45 S> */ B(JumpIfToBooleanTrue), U8(7),
B(LdaZero), B(LdaZero),
/* 56 E> */ B(TestLessThan), R(0), /* 56 E> */ B(TestLessThan), R(0),
B(JumpIfToBooleanFalse), U8(5), B(JumpIfFalse), U8(5),
/* 63 S> */ B(LdaSmi), U8(1), /* 63 S> */ B(LdaSmi), U8(1),
/* 75 S> */ B(Return), /* 75 S> */ B(Return),
B(LdaUndefined), B(LdaUndefined),
...@@ -43,10 +43,10 @@ bytecodes: [ ...@@ -43,10 +43,10 @@ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), U8(1), /* 42 S> */ B(LdaSmi), U8(1),
B(Star), R(0), B(Star), R(0),
/* 45 S> */ B(JumpIfToBooleanFalse), U8(5), /* 45 S> */ B(JumpIfToBooleanFalse), U8(10),
B(LdaZero), B(LdaZero),
/* 56 E> */ B(TestLessThan), R(0), /* 56 E> */ B(TestLessThan), R(0),
B(JumpIfToBooleanFalse), U8(5), B(JumpIfFalse), U8(5),
/* 63 S> */ B(LdaSmi), U8(1), /* 63 S> */ B(LdaSmi), U8(1),
/* 75 S> */ B(Return), /* 75 S> */ B(Return),
B(LdaUndefined), B(LdaUndefined),
...@@ -68,10 +68,10 @@ bytecodes: [ ...@@ -68,10 +68,10 @@ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), U8(1), /* 42 S> */ B(LdaSmi), U8(1),
B(Star), R(0), B(Star), R(0),
/* 45 S> */ B(JumpIfToBooleanTrue), U8(5), /* 45 S> */ B(JumpIfToBooleanTrue), U8(7),
B(LdaZero), B(LdaZero),
/* 57 E> */ B(TestLessThan), R(0), /* 57 E> */ B(TestLessThan), R(0),
B(JumpIfToBooleanFalse), U8(6), B(JumpIfFalse), U8(6),
B(LdaSmi), U8(2), B(LdaSmi), U8(2),
B(Jump), U8(4), B(Jump), U8(4),
B(LdaSmi), U8(3), B(LdaSmi), U8(3),
......
...@@ -13,14 +13,10 @@ snippet: " ...@@ -13,14 +13,10 @@ snippet: "
" "
frame size: 0 frame size: 0
parameter count: 1 parameter count: 1
bytecode array length: 12 bytecode array length: 4
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaSmi), U8(1), /* 34 S> */ B(LdaSmi), U8(2),
B(JumpIfToBooleanFalse), U8(6),
B(LdaSmi), U8(2),
B(Jump), U8(4),
B(LdaSmi), U8(3),
/* 52 S> */ B(Return), /* 52 S> */ B(Return),
] ]
constant pool: [ constant pool: [
...@@ -34,19 +30,58 @@ snippet: " ...@@ -34,19 +30,58 @@ snippet: "
" "
frame size: 0 frame size: 0
parameter count: 1 parameter count: 1
bytecode array length: 20 bytecode array length: 4
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaSmi), U8(1), /* 34 S> */ B(LdaSmi), U8(3),
B(JumpIfToBooleanFalse), U8(14), /* 60 S> */ B(Return),
]
constant pool: [
]
handlers: [
]
---
snippet: "
return 0 < 1 ? 2 : 3;
"
frame size: 1
parameter count: 1
bytecode array length: 17
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaZero),
B(Star), R(0),
B(LdaSmi), U8(1),
/* 43 E> */ B(TestLessThan), R(0),
B(JumpIfFalse), U8(6),
B(LdaSmi), U8(2), B(LdaSmi), U8(2),
B(JumpIfToBooleanFalse), U8(6),
B(LdaSmi), U8(3),
B(Jump), U8(4), B(Jump), U8(4),
B(LdaSmi), U8(4), B(LdaSmi), U8(3),
/* 56 S> */ B(Return),
]
constant pool: [
]
handlers: [
]
---
snippet: "
var x = 0;
return x ? 2 : 3;
"
frame size: 1
parameter count: 1
bytecode array length: 13
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaZero),
B(Star), R(0),
/* 45 S> */ B(JumpIfToBooleanFalse), U8(6),
B(LdaSmi), U8(2),
B(Jump), U8(4), B(Jump), U8(4),
B(LdaSmi), U8(5), B(LdaSmi), U8(3),
/* 60 S> */ B(Return), /* 63 S> */ B(Return),
] ]
constant pool: [ constant pool: [
] ]
......
...@@ -13,7 +13,7 @@ snippet: " ...@@ -13,7 +13,7 @@ snippet: "
" "
frame size: 16 frame size: 16
parameter count: 1 parameter count: 1
bytecode array length: 283 bytecode array length: 282
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
B(LdaZero), B(LdaZero),
...@@ -70,11 +70,10 @@ bytecodes: [ ...@@ -70,11 +70,10 @@ bytecodes: [
B(Star), R(11), B(Star), R(11),
B(LdaZero), B(LdaZero),
B(TestEqualStrict), R(3), B(TestEqualStrict), R(3),
B(JumpIfTrue), U8(5), B(JumpIfTrue), U8(123),
B(LdaUndefined), B(LdaUndefined),
B(TestEqualStrict), R(1), B(TestEqualStrict), R(1),
B(ToBooleanLogicalNot), B(JumpIfTrue), U8(118),
B(JumpIfFalse), U8(118),
B(LdrNamedProperty), R(1), U8(6), U8(13), R(5), B(LdrNamedProperty), R(1), U8(6), U8(13), R(5),
B(LdaNull), B(LdaNull),
B(TestEqual), R(5), B(TestEqual), R(5),
...@@ -144,7 +143,7 @@ constant pool: [ ...@@ -144,7 +143,7 @@ constant pool: [
handlers: [ handlers: [
[7, 121, 127], [7, 121, 127],
[10, 80, 82], [10, 80, 82],
[200, 210, 212], [199, 209, 211],
] ]
--- ---
...@@ -154,7 +153,7 @@ snippet: " ...@@ -154,7 +153,7 @@ snippet: "
" "
frame size: 17 frame size: 17
parameter count: 1 parameter count: 1
bytecode array length: 296 bytecode array length: 295
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaConstant), U8(0), /* 42 S> */ B(LdaConstant), U8(0),
...@@ -213,11 +212,10 @@ bytecodes: [ ...@@ -213,11 +212,10 @@ bytecodes: [
B(Star), R(12), B(Star), R(12),
B(LdaZero), B(LdaZero),
B(TestEqualStrict), R(3), B(TestEqualStrict), R(3),
B(JumpIfTrue), U8(5), B(JumpIfTrue), U8(123),
B(LdaUndefined), B(LdaUndefined),
B(TestEqualStrict), R(1), B(TestEqualStrict), R(1),
B(ToBooleanLogicalNot), B(JumpIfTrue), U8(118),
B(JumpIfFalse), U8(118),
B(LdrNamedProperty), R(1), U8(6), U8(13), R(5), B(LdrNamedProperty), R(1), U8(6), U8(13), R(5),
B(LdaNull), B(LdaNull),
B(TestEqual), R(5), B(TestEqual), R(5),
...@@ -292,7 +290,7 @@ constant pool: [ ...@@ -292,7 +290,7 @@ constant pool: [
handlers: [ handlers: [
[11, 124, 130], [11, 124, 130],
[14, 83, 85], [14, 83, 85],
[204, 214, 216], [203, 213, 215],
] ]
--- ---
...@@ -304,7 +302,7 @@ snippet: " ...@@ -304,7 +302,7 @@ snippet: "
" "
frame size: 16 frame size: 16
parameter count: 1 parameter count: 1
bytecode array length: 299 bytecode array length: 298
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
B(LdaZero), B(LdaZero),
...@@ -369,11 +367,10 @@ bytecodes: [ ...@@ -369,11 +367,10 @@ bytecodes: [
B(Star), R(11), B(Star), R(11),
B(LdaZero), B(LdaZero),
B(TestEqualStrict), R(3), B(TestEqualStrict), R(3),
B(JumpIfTrue), U8(5), B(JumpIfTrue), U8(123),
B(LdaUndefined), B(LdaUndefined),
B(TestEqualStrict), R(1), B(TestEqualStrict), R(1),
B(ToBooleanLogicalNot), B(JumpIfTrue), U8(118),
B(JumpIfFalse), U8(118),
B(LdrNamedProperty), R(1), U8(6), U8(13), R(5), B(LdrNamedProperty), R(1), U8(6), U8(13), R(5),
B(LdaNull), B(LdaNull),
B(TestEqual), R(5), B(TestEqual), R(5),
...@@ -443,7 +440,7 @@ constant pool: [ ...@@ -443,7 +440,7 @@ constant pool: [
handlers: [ handlers: [
[7, 137, 143], [7, 137, 143],
[10, 96, 98], [10, 96, 98],
[216, 226, 228], [215, 225, 227],
] ]
--- ---
...@@ -453,7 +450,7 @@ snippet: " ...@@ -453,7 +450,7 @@ snippet: "
" "
frame size: 15 frame size: 15
parameter count: 1 parameter count: 1
bytecode array length: 309 bytecode array length: 308
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 42 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(1), R(8), /* 42 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(1), R(8),
...@@ -515,11 +512,10 @@ bytecodes: [ ...@@ -515,11 +512,10 @@ bytecodes: [
B(Star), R(10), B(Star), R(10),
B(LdaZero), B(LdaZero),
B(TestEqualStrict), R(2), B(TestEqualStrict), R(2),
B(JumpIfTrue), U8(5), B(JumpIfTrue), U8(123),
B(LdaUndefined), B(LdaUndefined),
B(TestEqualStrict), R(0), B(TestEqualStrict), R(0),
B(ToBooleanLogicalNot), B(JumpIfTrue), U8(118),
B(JumpIfFalse), U8(118),
B(LdrNamedProperty), R(0), U8(8), U8(17), R(4), B(LdrNamedProperty), R(0), U8(8), U8(17), R(4),
B(LdaNull), B(LdaNull),
B(TestEqual), R(4), B(TestEqual), R(4),
...@@ -596,6 +592,6 @@ constant pool: [ ...@@ -596,6 +592,6 @@ constant pool: [
handlers: [ handlers: [
[15, 137, 143], [15, 137, 143],
[18, 96, 98], [18, 96, 98],
[217, 227, 229], [216, 226, 228],
] ]
...@@ -264,7 +264,7 @@ snippet: " ...@@ -264,7 +264,7 @@ snippet: "
" "
frame size: 18 frame size: 18
parameter count: 1 parameter count: 1
bytecode array length: 769 bytecode array length: 768
bytecodes: [ bytecodes: [
B(Ldar), R(new_target), B(Ldar), R(new_target),
B(JumpIfUndefined), U8(26), B(JumpIfUndefined), U8(26),
...@@ -316,7 +316,7 @@ bytecodes: [ ...@@ -316,7 +316,7 @@ bytecodes: [
B(Star), R(6), B(Star), R(6),
B(LdaZero), B(LdaZero),
B(Star), R(5), B(Star), R(5),
B(JumpConstant), U8(16), B(JumpConstant), U8(17),
B(Ldar), R(10), B(Ldar), R(10),
/* 11 E> */ B(Throw), /* 11 E> */ B(Throw),
B(LdaConstant), U8(0), B(LdaConstant), U8(0),
...@@ -452,12 +452,11 @@ bytecodes: [ ...@@ -452,12 +452,11 @@ bytecodes: [
B(LdrContextSlot), R(1), U8(9), R(11), B(LdrContextSlot), R(1), U8(9), R(11),
B(LdaZero), B(LdaZero),
B(TestEqualStrict), R(11), B(TestEqualStrict), R(11),
B(JumpIfTrue), U8(9), B(JumpIfTrueConstant), U8(15),
B(LdrContextSlot), R(1), U8(7), R(11), B(LdrContextSlot), R(1), U8(7), R(11),
B(LdaUndefined), B(LdaUndefined),
B(TestEqualStrict), R(11), B(TestEqualStrict), R(11),
B(ToBooleanLogicalNot), B(JumpIfTrueConstant), U8(16),
B(JumpIfFalseConstant), U8(15),
B(LdrContextSlot), R(1), U8(7), R(11), B(LdrContextSlot), R(1), U8(7), R(11),
B(LdaNamedProperty), R(11), U8(12), U8(13), B(LdaNamedProperty), R(11), U8(12), U8(13),
B(StaContextSlot), R(1), U8(11), B(StaContextSlot), R(1), U8(11),
...@@ -596,11 +595,12 @@ constant pool: [ ...@@ -596,11 +595,12 @@ constant pool: [
InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE,
kInstanceTypeDontCare, kInstanceTypeDontCare,
kInstanceTypeDontCare, kInstanceTypeDontCare,
kInstanceTypeDontCare,
] ]
handlers: [ handlers: [
[41, 688, 694], [41, 687, 693],
[147, 442, 448], [147, 442, 448],
[150, 396, 398], [150, 396, 398],
[545, 557, 559], [544, 556, 558],
] ]
...@@ -737,3 +737,47 @@ constant pool: [ ...@@ -737,3 +737,47 @@ constant pool: [
handlers: [ handlers: [
] ]
---
snippet: "
function f(a, b) {
if (a == b || a < 0) {
return 1;
} else if (a > 0 && b > 0) {
return 0;
} else {
return -1;
}
};
f(-1, 1);
"
frame size: 0
parameter count: 3
bytecode array length: 32
bytecodes: [
/* 10 E> */ B(StackCheck),
/* 21 S> */ B(Ldar), R(arg1),
/* 27 E> */ B(TestEqual), R(arg0),
B(JumpIfTrue), U8(7),
B(LdaZero),
/* 37 E> */ B(TestLessThan), R(arg0),
B(JumpIfFalse), U8(5),
/* 48 S> */ B(LdaSmi), U8(1),
/* 133 S> */ B(Return),
/* 67 S> */ B(LdaZero),
/* 73 E> */ B(TestGreaterThan), R(arg0),
B(JumpIfFalse), U8(9),
B(LdaZero),
/* 82 E> */ B(TestGreaterThan), R(arg1),
B(JumpIfFalse), U8(4),
/* 93 S> */ B(LdaZero),
/* 133 S> */ B(Return),
/* 118 S> */ B(LdaSmi), U8(-1),
/* 133 S> */ B(Return),
B(LdaUndefined),
/* 133 S> */ B(Return),
]
constant pool: [
]
handlers: [
]
...@@ -705,6 +705,17 @@ TEST(IfConditions) { ...@@ -705,6 +705,17 @@ TEST(IfConditions) {
" }\n" " }\n"
"};\n" "};\n"
"f();\n", "f();\n",
"function f(a, b) {\n"
" if (a == b || a < 0) {\n"
" return 1;\n"
" } else if (a > 0 && b > 0) {\n"
" return 0;\n"
" } else {\n"
" return -1;\n"
" }\n"
"};\n"
"f(-1, 1);\n",
}; };
CHECK(CompareTexts(BuildActual(printer, snippets), CHECK(CompareTexts(BuildActual(printer, snippets),
...@@ -1615,6 +1626,11 @@ TEST(Conditional) { ...@@ -1615,6 +1626,11 @@ TEST(Conditional) {
"return 1 ? 2 : 3;\n", "return 1 ? 2 : 3;\n",
"return 1 ? 2 ? 3 : 4 : 5;\n", "return 1 ? 2 ? 3 : 4 : 5;\n",
"return 0 < 1 ? 2 : 3;\n",
"var x = 0;\n"
"return x ? 2 : 3;\n",
}; };
CHECK(CompareTexts(BuildActual(printer, snippets), CHECK(CompareTexts(BuildActual(printer, snippets),
......
...@@ -287,7 +287,8 @@ TEST(MultipleFuncsConditional) { ...@@ -287,7 +287,8 @@ TEST(MultipleFuncsConditional) {
v8::HandleScope scope(CcTest::isolate()); v8::HandleScope scope(CcTest::isolate());
v8::Local<v8::Script> script = Compile(CcTest::isolate(), v8::Local<v8::Script> script = Compile(CcTest::isolate(),
"fun1 = 0 ?\n" "var x = 0;\n"
"fun1 = x ?\n"
" function() { return 1; } :\n" " function() { return 1; } :\n"
" function() { return 2; }"); " function() { return 2; }");
CheckFunctionName(script, "return 1", "fun1"); CheckFunctionName(script, "return 1", "fun1");
...@@ -301,9 +302,10 @@ TEST(MultipleFuncsInLiteral) { ...@@ -301,9 +302,10 @@ TEST(MultipleFuncsInLiteral) {
v8::Local<v8::Script> script = v8::Local<v8::Script> script =
Compile(CcTest::isolate(), Compile(CcTest::isolate(),
"var x = 0;\n"
"function MyClass() {}\n" "function MyClass() {}\n"
"MyClass.prototype = {\n" "MyClass.prototype = {\n"
" method1: 0 ? function() { return 1; } :\n" " method1: x ? function() { return 1; } :\n"
" function() { return 2; } }"); " function() { return 2; } }");
CheckFunctionName(script, "return 1", "MyClass.method1"); CheckFunctionName(script, "return 1", "MyClass.method1");
CheckFunctionName(script, "return 2", "MyClass.method1"); CheckFunctionName(script, "return 2", "MyClass.method1");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment