Commit 49420760 authored by Peter Marshall's avatar Peter Marshall Committed by Commit Bot

[cleanup] Don't declare inline runtime functions by default

For each intrinsic/runtime function we define in runtime.h, an inline
version is automatically declared. We only ever use 24 of the inline
functions. Even though we don't call the other ones, macro magic means
they still take up space by existing in various arrays and tables like
kIntrinsicFunctions. They also create code in switch statements.

Some drive-by cleanups:
 - Remove the switch in NameForRuntimeId() and just use the table of
   runtime functions to lookup the name directly.
 - Remove tests for IsFunction, ClassOf and StringAdd intrinsics as
   they are the last users of the inline versions of these.
 - Remove the MaxSmi inline version as it is only used in tests.

Saves 64 KiB binary size.

Change-Id: I4c870ddacd2655ffcffa97d93200ed8f853752f5
Reviewed-on: https://chromium-review.googlesource.com/c/1261939
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56412}
parent 4fd92b25
......@@ -291,10 +291,8 @@ M_(FPCR, AHP_mask | DN_mask | FZ_mask | RMode_mask)
const uint32_t Name##_mask = ((1 << Name##_width) - 1) << LowBit;
#define DECLARE_INSTRUCTION_FIELDS_OFFSETS(Name, HighBit, LowBit, unused_1) \
DECLARE_FIELDS_OFFSETS(Name, HighBit, LowBit, unused_1, unused_2)
#define NOTHING(A, B)
INSTRUCTION_FIELDS_LIST(DECLARE_INSTRUCTION_FIELDS_OFFSETS)
SYSTEM_REGISTER_FIELDS_LIST(DECLARE_FIELDS_OFFSETS, NOTHING)
#undef NOTHING
#undef DECLARE_FIELDS_OFFSETS
#undef DECLARE_INSTRUCTION_FIELDS_OFFSETS
......
......@@ -14,6 +14,9 @@
// No-op macro which is used to work around MSVC's funky VA_ARGS support.
#define EXPAND(x) x
// This macro does nothing. That's all.
#define NOTHING(...)
// TODO(all) Replace all uses of this macro with C++'s offsetof. To do that, we
// have to make sure that only standard-layout types and simple field
// designators are used.
......
......@@ -241,7 +241,7 @@ void DebugEvaluate::ContextBuilder::UpdateValues() {
namespace {
bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) {
// Use macro to include both inlined and non-inlined version of an intrinsic.
// Use macro to include only the non-inlined version of an intrinsic.
#define INTRINSIC_WHITELIST(V) \
/* Conversions */ \
V(NumberToString) \
......@@ -348,12 +348,16 @@ bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) {
V(OptimizeOsr) \
V(UnblockConcurrentRecompilation)
#define CASE(Name) \
case Runtime::k##Name: \
case Runtime::kInline##Name:
// Intrinsics with inline versions have to be whitelisted here a second time.
#define INLINE_INTRINSIC_WHITELIST(V) \
V(Call) \
V(IsJSReceiver)
#define CASE(Name) case Runtime::k##Name:
#define INLINE_CASE(Name) case Runtime::kInline##Name:
switch (id) {
INTRINSIC_WHITELIST(CASE)
INLINE_INTRINSIC_WHITELIST(INLINE_CASE)
return true;
default:
if (FLAG_trace_side_effect_free_debug_evaluate) {
......@@ -364,7 +368,9 @@ bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) {
}
#undef CASE
#undef INLINE_CASE
#undef INTRINSIC_WHITELIST
#undef INLINE_INTRINSIC_WHITELIST
}
#ifdef DEBUG
......@@ -390,9 +396,7 @@ bool BuiltinToIntrinsicHasNoSideEffect(Builtins::Name builtin_id,
case Builtin: \
return (__VA_ARGS__ false);
#define MATCH(Intrinsic) \
intrinsic_id == Runtime::k##Intrinsic || \
intrinsic_id == Runtime::kInline##Intrinsic ||
#define MATCH(Intrinsic) intrinsic_id == Runtime::k##Intrinsic ||
switch (builtin_id) {
BUILTIN_INTRINSIC_WHITELIST(CASE, MATCH)
......
......@@ -30,7 +30,8 @@ class ExternalReferenceTable {
BUILTIN_LIST_C(COUNT_C_BUILTIN);
#undef COUNT_C_BUILTIN
static constexpr int kRuntimeReferenceCount =
Runtime::kNumFunctions / 2; // Don't count dupe kInline... functions.
Runtime::kNumFunctions -
Runtime::kNumInlineFunctions; // Don't count dupe kInline... functions.
static constexpr int kIsolateAddressReferenceCount = kIsolateAddressCount;
static constexpr int kAccessorReferenceCount =
Accessors::kAccessorInfoCount + Accessors::kAccessorSetterCount;
......
......@@ -71,18 +71,8 @@ uint32_t BytecodeDecoder::DecodeUnsignedOperand(Address operand_start,
namespace {
const char* NameForRuntimeId(uint32_t idx) {
switch (idx) {
#define CASE(name, nargs, ressize) \
case Runtime::k##name: \
return #name; \
case Runtime::kInline##name: \
return "_" #name;
FOR_EACH_INTRINSIC(CASE)
#undef CASE
default:
UNREACHABLE();
}
const char* NameForRuntimeId(Runtime::FunctionId idx) {
return Runtime::FunctionForId(idx)->name;
}
const char* NameForNativeContextIndex(uint32_t idx) {
......@@ -160,8 +150,9 @@ std::ostream& BytecodeDecoder::Decode(std::ostream& os,
break;
}
case interpreter::OperandType::kRuntimeId:
os << "[" << NameForRuntimeId(DecodeUnsignedOperand(
operand_start, op_type, operand_scale))
os << "["
<< NameForRuntimeId(static_cast<Runtime::FunctionId>(
DecodeUnsignedOperand(operand_start, op_type, operand_scale)))
<< "]";
break;
case interpreter::OperandType::kImm:
......
......@@ -45,9 +45,7 @@ FOR_EACH_INTRINSIC_RETURN_PAIR(P)
,
static const Runtime::Function kIntrinsicFunctions[] = {
FOR_EACH_INTRINSIC(F)
FOR_EACH_INTRINSIC(I)
};
FOR_EACH_INTRINSIC(F) FOR_EACH_INLINE_INTRINSIC(I)};
#undef I
#undef F
......
This diff is collapsed.
......@@ -20,21 +20,6 @@ TEST(Call) {
T.CheckCall(T.Val("6x"), T.NewObject("({d:'x'})"), T.NewObject("f"));
}
TEST(ClassOf) {
FunctionTester T("(function(a) { return %_ClassOf(a); })", flags);
T.CheckCall(T.Val("Function"), T.NewObject("(function() {})"));
T.CheckCall(T.Val("Array"), T.NewObject("([1])"));
T.CheckCall(T.Val("Object"), T.NewObject("({})"));
T.CheckCall(T.Val("RegExp"), T.NewObject("(/x/)"));
T.CheckCall(T.null(), T.undefined());
T.CheckCall(T.null(), T.null());
T.CheckCall(T.null(), T.Val("x"));
T.CheckCall(T.null(), T.Val(1));
}
TEST(IsArray) {
FunctionTester T("(function(a) { return %_IsArray(a); })", flags);
......@@ -50,21 +35,6 @@ TEST(IsArray) {
}
TEST(IsFunction) {
FunctionTester T("(function(a) { return %_IsFunction(a); })", flags);
T.CheckFalse(T.NewObject("new Date()"));
T.CheckTrue(T.NewObject("(function() {})"));
T.CheckFalse(T.NewObject("([1])"));
T.CheckFalse(T.NewObject("({})"));
T.CheckFalse(T.NewObject("(/x/)"));
T.CheckFalse(T.undefined());
T.CheckFalse(T.null());
T.CheckFalse(T.Val("x"));
T.CheckFalse(T.Val(1));
}
TEST(IsSmi) {
FunctionTester T("(function(a) { return %_IsSmi(a); })", flags);
......@@ -81,15 +51,6 @@ TEST(IsSmi) {
T.CheckFalse(T.Val(-2.3));
}
TEST(StringAdd) {
FunctionTester T("(function(a,b) { return %_StringAdd(a,b); })", flags);
T.CheckCall(T.Val("aaabbb"), T.Val("aaa"), T.Val("bbb"));
T.CheckCall(T.Val("aaa"), T.Val("aaa"), T.Val(""));
T.CheckCall(T.Val("bbb"), T.Val(""), T.Val("bbb"));
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -212,7 +212,7 @@ tests.push(function TestFromTypedArraySpeciesNeutersBuffer(constr) {
});
tests.push(function TestLengthIsMaxSmi(constr) {
var myObject = { 0: 5, 1: 6, length: %_MaxSmi() + 1 };
var myObject = { 0: 5, 1: 6, length: %MaxSmi() + 1 };
assertThrows(function() {
new constr(myObject);
......@@ -258,7 +258,7 @@ tests.push(function TestOffsetIsUsed(constr) {
});
tests.push(function TestLengthIsNonSmiNegativeNumber(constr) {
var ta = new constr({length: -%_MaxSmi() - 2});
var ta = new constr({length: -%MaxSmi() - 2});
assertEquals(0, ta.length);
});
......
......@@ -5,7 +5,7 @@
// Flags: --allow-natives-syntax --mock-arraybuffer-allocator
(function TestBufferByteLengthNonSmi() {
var non_smi_byte_length = %_MaxSmi() + 1;
var non_smi_byte_length = %MaxSmi() + 1;
var buffer = new ArrayBuffer(non_smi_byte_length);
......@@ -20,7 +20,7 @@
})();
(function TestByteOffsetNonSmi() {
var non_smi_byte_length = %_MaxSmi() + 11;
var non_smi_byte_length = %MaxSmi() + 11;
var buffer = new ArrayBuffer(non_smi_byte_length);
......
......@@ -5,13 +5,13 @@
// Flags: --allow-natives-syntax --mock-arraybuffer-allocator
(function TestBufferByteLengthNonSmi() {
const source_buffer_length = %_MaxSmi() + 1;
const source_buffer_length = %MaxSmi() + 1;
const source_buffer = new ArrayBuffer(source_buffer_length);
const source = new Uint16Array(source_buffer);
assertEquals(source_buffer_length, source_buffer.byteLength);
assertEquals(source_buffer_length / 2, source.length);
const target_buffer_length = %_MaxSmi() - 1;
const target_buffer_length = %MaxSmi() - 1;
const target_buffer = new ArrayBuffer(target_buffer_length);
const target = new Uint16Array(target_buffer);
assertEquals(target_buffer_length, target_buffer.byteLength);
......
......@@ -26,7 +26,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --nostress-opt --allow-natives-syntax --mock-arraybuffer-allocator
var maxSize = %_MaxSmi() + 1;
var maxSize = %MaxSmi() + 1;
var ab;
// Allocate the largest ArrayBuffer we can on this architecture.
......
......@@ -27,7 +27,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --nostress-opt --allow-natives-syntax
var maxSize = %_MaxSmi() + 1;
var maxSize = %MaxSmi() + 1;
function TestArray(constr) {
assertThrows(function() {
new constr(maxSize);
......
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