Coverage for /Syzygy/optimize/transforms/inlining_transform_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
99.6%2472480.C++test

Line-by-line coverage:

   1    :  // Copyright 2013 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  #include "syzygy/optimize/transforms/inlining_transform.h"
  16    :  
  17    :  #include "gmock/gmock.h"
  18    :  #include "gtest/gtest.h"
  19    :  #include "syzygy/block_graph/basic_block.h"
  20    :  #include "syzygy/block_graph/basic_block_assembler.h"
  21    :  #include "syzygy/block_graph/basic_block_decomposer.h"
  22    :  #include "syzygy/block_graph/basic_block_subgraph.h"
  23    :  #include "syzygy/block_graph/block_builder.h"
  24    :  #include "syzygy/block_graph/block_graph.h"
  25    :  #include "syzygy/block_graph/unittest_util.h"
  26    :  #include "syzygy/optimize/application_profile.h"
  27    :  #include "syzygy/pe/pe_transform_policy.h"
  28    :  
  29    :  namespace optimize {
  30    :  namespace transforms {
  31    :  namespace {
  32    :  
  33    :  using block_graph::BasicBlock;
  34    :  using block_graph::BasicBlockAssembler;
  35    :  using block_graph::BasicBlockDecomposer;
  36    :  using block_graph::BasicBlockReference;
  37    :  using block_graph::BasicBlockSubGraph;
  38    :  using block_graph::BlockBuilder;
  39    :  using block_graph::BlockGraph;
  40    :  using block_graph::Displacement;
  41    :  using block_graph::Immediate;
  42    :  using block_graph::Instruction;
  43    :  using block_graph::Operand;
  44    :  using block_graph::Successor;
  45    :  using pe::ImageLayout;
  46    :  using testing::ElementsAreArray;
  47    :  
  48    :  typedef block_graph::BasicBlockSubGraph::BasicCodeBlock BasicCodeBlock;
  49    :  
  50    :  // This enum is used to drive the contents of the callee.
  51    :  enum CalleeKind {
  52    :    // Block DirectTrampoline
  53    :    //   dummy: jmp target
  54    :    kDirectTrampoline,
  55    :    // Block IndirectTrampoline
  56    :    //   dummy: jmp [target]
  57    :    kIndirectTrampoline,
  58    :    // Block RecursiveTrampoline
  59    :    //   dummy: jmp dummy
  60    :    kRecursiveTrampoline,
  61    :  };
  62    :  
  63    :  const uint8 kData[] = { 0x01, 0x02, 0x03, 0x04 };
  64    :  
  65    :  // _asm ret
  66    :  const uint8 kCodeRet[] = { 0xC3 };
  67    :  
  68    :  // _asm push ebp
  69    :  // _asm mov ebp, esp
  70    :  // _asm pop ebp
  71    :  // _asm ret
  72    :  const uint8 kCodeEmpty[] = { 0x55, 0x8B, 0xEC, 0x5D, 0xC3 };
  73    :  
  74    :  // _asm push ebp
  75    :  // _asm mov ebp, esp
  76    :  // _asm pop ebp
  77    :  // _asm xor eax, eax
  78    :  // _asm ret
  79    :  const uint8 kCodeOptimizeRet0[] = { 0x55, 0x8B, 0xEC, 0x5D, 0x33, 0xC0, 0xC3 };
  80    :  
  81    :  // _asm ret8
  82    :  const uint8 kCodeRetWithOffset[] = { 0xC2, 0x08, 0x00 };
  83    :  
  84    :  // _asm lea esp, [esp + 8]
  85    :  const uint8 kCodeLeaEsp8[] = { 0x8D, 0x64, 0x24, 0x08, 0xC3 };
  86    :  
  87    :  // _asm xor eax, eax
  88    :  // _asm ret
  89    :  const uint8 kCodeRet0[] = { 0x33, 0xC0, 0xC3 };
  90    :  
  91    :  // _asm xor eax, eax
  92    :  const uint8 kCodeMov0[] = { 0x33, 0xC0 };
  93    :  
  94    :  // _asm mov eax, 2Ah
  95    :  // _asm ret
  96    :  const uint8 kCodeRet42[] = { 0xB8, 0x2A, 0x00, 0x00, 0x00, 0xC3 };
  97    :  
  98    :  // _asm xor eax, eax
  99    :  // _asm mov eax, 2Ah
 100    :  // _asm ret
 101    :  const uint8 kCodeRetBoth[] = { 0x33, 0xC0, 0xB8, 0x2A, 0x00, 0x00, 0x00, 0xC3 };
 102    :  
 103    :  // _asm mov eax, esp
 104    :  // _asm ret
 105    :  const uint8 kCodeMovStack[] = { 0x8B, 0xC4, 0xC3 };
 106    :  
 107    :  // _asm ret (16x)
 108    :  const uint8 kCodeBig[] = {
 109    :      0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,
 110    :      0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3 };
 111    :  
 112    :  // _asm je  here
 113    :  // _asm xor eax, eax
 114    :  // here:
 115    :  // _asm ret
 116    :  const uint8 kCodeJump[] = { 0x74, 0x02, 0x33, 0xC0, 0xC3 };
 117    :  
 118    :  // here:
 119    :  // _asm or  eax,eax
 120    :  // _asm jne here
 121    :  // _asm ret
 122    :  const uint8 kCodeSelfJump[] = { 0x0B, 0xC0, 0x75, 0xFC, 0xC3 };
 123    :  
 124    :  // _asm call  dword ptr [eax]
 125    :  // _asm ret
 126    :  const uint8 kCodeIndirectCall[] = { 0xFF, 0x55, 0xF8, 0xC3 };
 127    :  
 128    :  // _asm push 2
 129    :  // _asm pop eax
 130    :  // _asm ret
 131    :  const uint8 kStackCst[] = { 0x6A, 0x02, 0x58, 0xC3 };
 132    :  
 133    :  class TestInliningTransform : public InliningTransform {
 134    :   public:
 135    :    using InliningTransform::subgraph_cache_;
 136    :  };
 137    :  
 138    :  class InliningTransformTest : public testing::Test {
 139    :   public:
 140    :    InliningTransformTest()
 141    :        : data_(NULL),
 142    :          caller_(NULL),
 143    :          callee_(NULL),
 144    :          image_(&block_graph_),
 145  E :          profile_(&image_) {
 146  E :    }
 147    :  
 148  E :    virtual void SetUp() {
 149    :      caller_ =
 150  E :          block_graph_.AddBlock(BlockGraph::CODE_BLOCK, sizeof(kCodeRet), "ret");
 151  E :      DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), caller_);
 152  E :      caller_->SetData(kCodeRet, sizeof(kCodeRet));
 153  E :      caller_->SetLabel(0, "code", BlockGraph::CODE_LABEL);
 154    :  
 155  E :      data_ = block_graph_.AddBlock(BlockGraph::DATA_BLOCK, sizeof(kData), "int");
 156  E :      DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), data_);
 157  E :      data_->SetData(kData, sizeof(kData));
 158  E :    }
 159    :  
 160    :   protected:
 161    :    void AddBlockFromBuffer(const uint8* data,
 162    :                            size_t length,
 163    :                            BlockGraph::Block** block);
 164    :    void CreateCalleeBlock(CalleeKind kind,
 165    :                           BlockGraph::Block* target,
 166    :                           BlockGraph::Block** callee);
 167    :    void CreateCallSiteToBlock(BlockGraph::Block* callee);
 168    :    void ApplyTransformOnCaller();
 169    :    void SaveCaller();
 170    :  
 171    :    pe::PETransformPolicy policy_;
 172    :    BlockGraph block_graph_;
 173    :    BlockGraph::Block* data_;
 174    :    BlockGraph::Block* caller_;
 175    :    BlockGraph::Block* callee_;
 176    :    std::vector<uint8> original_;
 177    :    BasicBlockSubGraph callee_subgraph_;
 178    :    ImageLayout image_;
 179    :    ApplicationProfile profile_;
 180    :    SubGraphProfile subgraph_profile_;
 181    :  };
 182    :  
 183    :  void InliningTransformTest::AddBlockFromBuffer(const uint8* data,
 184    :                                                 size_t length,
 185  E :                                                 BlockGraph::Block** block) {
 186  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block**>(NULL), block);
 187  E :    *block = block_graph_.AddBlock(BlockGraph::CODE_BLOCK, length, "test");
 188  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), *block);
 189  E :    (*block)->SetData(data, length);
 190  E :    (*block)->SetLabel(0, "code", BlockGraph::CODE_LABEL);
 191  E :  }
 192    :  
 193    :  // Produce a callee block. The content of the body is determined by |kind|.
 194    :  void InliningTransformTest::CreateCalleeBlock(CalleeKind kind,
 195    :                                                BlockGraph::Block* target,
 196  E :                                                BlockGraph::Block** callee) {
 197  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block**>(NULL), callee);
 198  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), *callee);
 199    :  
 200    :    // Decompose to subgraph.
 201  E :    BasicBlockSubGraph subgraph;
 202  E :    BasicBlockDecomposer decomposer(*callee, &subgraph);
 203  E :    ASSERT_TRUE(decomposer.Decompose());
 204    :  
 205    :    // Retrieve the single basic block.
 206  E :    ASSERT_EQ(1U, subgraph.basic_blocks().size());
 207  E :    BasicCodeBlock* code = BasicCodeBlock::Cast(*subgraph.basic_blocks().begin());
 208  E :    DCHECK_NE(reinterpret_cast<BasicCodeBlock*>(NULL), code);
 209    :  
 210    :    // Clear instructions and open an assembler at the start of the basic block.
 211  E :    BasicBlock::Instructions& instructions = code->instructions();
 212  E :    instructions.clear();
 213  E :    BasicBlockAssembler assembler(instructions.begin(), &instructions);
 214    :  
 215  E :    switch (kind) {
 216    :      case kRecursiveTrampoline:
 217  E :        assembler.jmp(Immediate(code));
 218  E :        break;
 219    :      case kDirectTrampoline: {
 220    :        Successor successor(
 221    :            Successor::kConditionTrue,
 222    :            BasicBlockReference(BlockGraph::PC_RELATIVE_REF, 4, target, 0, 0),
 223  E :            4);
 224  E :        code->successors().push_back(successor);
 225  E :        break;
 226    :      }
 227    :      case kIndirectTrampoline:
 228  E :        assembler.jmp(Operand(Displacement(target, 0, 0)));
 229  E :        break;
 230    :      default:
 231  i :        NOTREACHED() << "Invalid callee kind.";
 232    :    }
 233    :  
 234    :    // Rebuild block.
 235  E :    BlockBuilder builder(&block_graph_);
 236  E :    ASSERT_TRUE(builder.Merge(&subgraph));
 237  E :    CHECK_EQ(1u, builder.new_blocks().size());
 238  E :    *callee = *builder.new_blocks().begin();
 239  E :  };
 240    :  
 241  E :  void InliningTransformTest::CreateCallSiteToBlock(BlockGraph::Block* callee) {
 242  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), caller_);
 243  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), callee);
 244    :  
 245    :    // Decompose to subgraph.
 246  E :    BasicBlockSubGraph subgraph;
 247  E :    BasicBlockDecomposer decomposer(caller_, &subgraph);
 248  E :    ASSERT_TRUE(decomposer.Decompose());
 249    :  
 250    :    // Retrieve the single basic block.
 251  E :    ASSERT_EQ(1U, subgraph.basic_blocks().size());
 252  E :    BasicCodeBlock* code = BasicCodeBlock::Cast(*subgraph.basic_blocks().begin());
 253  E :    DCHECK_NE(reinterpret_cast<BasicCodeBlock*>(NULL), code);
 254    :  
 255    :    // Encode a call at the entry of this basic block.
 256  E :    BasicBlock::Instructions& instructions = code->instructions();
 257  E :    BasicBlockAssembler assembler(instructions.begin(), &instructions);
 258  E :    assembler.call(Immediate(callee, 0, 0));
 259    :  
 260    :    // Rebuild block.
 261  E :    BlockBuilder builder(&block_graph_);
 262  E :    ASSERT_TRUE(builder.Merge(&subgraph));
 263  E :    CHECK_EQ(1u, builder.new_blocks().size());
 264  E :    caller_ = *builder.new_blocks().begin();
 265    :  
 266    :    // Keep track of the original raw bytes from the caller block.
 267  E :    SaveCaller();
 268  E :  };
 269    :  
 270  E :  void InliningTransformTest::SaveCaller() {
 271    :    // Keep track of the original raw bytes from the caller block.
 272  E :    ASSERT_LT(0U, caller_->size());
 273  E :    original_.resize(caller_->size());
 274  E :    ::memcpy(&original_[0], caller_->data(), caller_->size());
 275  E :  }
 276    :  
 277  E :  void InliningTransformTest::ApplyTransformOnCaller() {
 278    :    // Decompose to subgraph.
 279  E :    BasicBlockSubGraph subgraph;
 280  E :    BasicBlockDecomposer decomposer(caller_, &subgraph);
 281  E :    ASSERT_TRUE(decomposer.Decompose());
 282    :  
 283    :    // Apply inlining transform.
 284  E :    InliningTransform tx;
 285    :    ASSERT_TRUE(
 286    :        tx.TransformBasicBlockSubGraph(&policy_, &block_graph_, &subgraph,
 287  E :                                       &profile_, &subgraph_profile_));
 288    :  
 289    :    // Rebuild block.
 290  E :    BlockBuilder builder(&block_graph_);
 291  E :    ASSERT_TRUE(builder.Merge(&subgraph));
 292  E :    CHECK_EQ(1u, builder.new_blocks().size());
 293  E :    caller_ = *builder.new_blocks().begin();
 294  E :  }
 295    :  
 296    :  }  // namespace
 297    :  
 298  E :  TEST_F(InliningTransformTest, SubgraphCache) {
 299  E :    TestInliningTransform tx;
 300    :  
 301    :    // Create a valid inlining candidate.
 302    :    ASSERT_NO_FATAL_FAILURE(
 303  E :        AddBlockFromBuffer(kCodeRet42, sizeof(kCodeRet42), &callee_));
 304  E :    ASSERT_NO_FATAL_FAILURE(CreateCallSiteToBlock(callee_));
 305    :  
 306    :    // The cache must be empty.
 307  E :    EXPECT_TRUE(tx.subgraph_cache_.empty());
 308    :  
 309    :    // Decompose to subgraph.
 310  E :    BasicBlockSubGraph subgraph;
 311  E :    BasicBlockDecomposer decomposer(caller_, &subgraph);
 312  E :    ASSERT_TRUE(decomposer.Decompose());
 313    :  
 314    :    // Apply inlining transform.
 315    :    ASSERT_TRUE(
 316    :        tx.TransformBasicBlockSubGraph(&policy_, &block_graph_, &subgraph,
 317  E :                                       &profile_, &subgraph_profile_));
 318    :  
 319    :    // Expect the subgraph to be cached.
 320  E :    EXPECT_EQ(1U, tx.subgraph_cache_.size());
 321  E :  }
 322    :  
 323  E :  TEST_F(InliningTransformTest, PreTransformValidation) {
 324    :    ASSERT_NO_FATAL_FAILURE(
 325  E :        AddBlockFromBuffer(kCodeRet, sizeof(kCodeRet), &callee_));
 326  E :    ASSERT_NO_FATAL_FAILURE(CreateCallSiteToBlock(callee_));
 327    :  
 328    :    // Caller and callee aren't modified without applying the transform.
 329  E :    EXPECT_EQ(6U, caller_->size());
 330  E :    EXPECT_EQ(1U, callee_->size());
 331  E :    EXPECT_THAT(kCodeRet, ElementsAreArray(callee_->data(), callee_->size()));
 332  E :  }
 333    :  
 334  E :  TEST_F(InliningTransformTest, InlineTrivialRet) {
 335    :    ASSERT_NO_FATAL_FAILURE(
 336  E :        AddBlockFromBuffer(kCodeRet, sizeof(kCodeRet), &callee_));
 337  E :    ASSERT_NO_FATAL_FAILURE(CreateCallSiteToBlock(callee_));
 338  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformOnCaller());
 339    :  
 340    :    // Expect inlining expansion on caller.
 341  E :    EXPECT_THAT(kCodeRet, ElementsAreArray(caller_->data(), caller_->size()));
 342  E :    EXPECT_THAT(kCodeRet, ElementsAreArray(callee_->data(), callee_->size()));
 343  E :  }
 344    :  
 345  E :  TEST_F(InliningTransformTest, InlineTrivialRet0) {
 346    :    ASSERT_NO_FATAL_FAILURE(
 347  E :        AddBlockFromBuffer(kCodeRet0, sizeof(kCodeRet0), &callee_));
 348  E :    ASSERT_NO_FATAL_FAILURE(CreateCallSiteToBlock(callee_));
 349  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformOnCaller());
 350    :  
 351  E :    EXPECT_THAT(kCodeRet0, ElementsAreArray(caller_->data(), caller_->size()));
 352  E :    EXPECT_THAT(kCodeRet0, ElementsAreArray(callee_->data(), callee_->size()));
 353  E :  }
 354    :  
 355  E :  TEST_F(InliningTransformTest, InlineTrivialRet42) {
 356    :    ASSERT_NO_FATAL_FAILURE(
 357  E :        AddBlockFromBuffer(kCodeRet42, sizeof(kCodeRet42), &callee_));
 358  E :    ASSERT_NO_FATAL_FAILURE(CreateCallSiteToBlock(callee_));
 359  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformOnCaller());
 360    :  
 361  E :    EXPECT_THAT(kCodeRet42, ElementsAreArray(caller_->data(), caller_->size()));
 362  E :    EXPECT_THAT(kCodeRet42, ElementsAreArray(callee_->data(), callee_->size()));
 363  E :  }
 364    :  
 365  E :  TEST_F(InliningTransformTest, InlineEmptyBody) {
 366    :    ASSERT_NO_FATAL_FAILURE(
 367  E :        AddBlockFromBuffer(kCodeEmpty, sizeof(kCodeEmpty), &callee_));
 368  E :    ASSERT_NO_FATAL_FAILURE(CreateCallSiteToBlock(callee_));
 369  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformOnCaller());
 370    :  
 371  E :    EXPECT_THAT(kCodeRet, ElementsAreArray(caller_->data(), caller_->size()));
 372  E :  }
 373    :  
 374  E :  TEST_F(InliningTransformTest, InlineTrivialTwoCalls) {
 375  E :    BlockGraph::Block* callee1 = NULL;
 376  E :    BlockGraph::Block* callee2 = NULL;
 377    :  
 378    :    ASSERT_NO_FATAL_FAILURE(
 379  E :        AddBlockFromBuffer(kCodeRet0, sizeof(kCodeRet0), &callee1));
 380    :    ASSERT_NO_FATAL_FAILURE(
 381  E :        AddBlockFromBuffer(kCodeRet42, sizeof(kCodeRet42), &callee2));
 382    :  
 383  E :    ASSERT_NO_FATAL_FAILURE(CreateCallSiteToBlock(callee2));
 384  E :    ASSERT_NO_FATAL_FAILURE(CreateCallSiteToBlock(callee1));
 385    :  
 386  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformOnCaller());
 387    :  
 388    :    // Expect both calls to be inlined and instructions to be in the right order.
 389    :    EXPECT_THAT(kCodeRetBoth,
 390  E :                ElementsAreArray(caller_->data(), caller_->size()));
 391  E :  }
 392    :  
 393  E :  TEST_F(InliningTransformTest, InlineReturnWithOffset) {
 394    :    ASSERT_NO_FATAL_FAILURE(
 395    :        AddBlockFromBuffer(kCodeRetWithOffset,
 396    :                           sizeof(kCodeRetWithOffset),
 397  E :                           &callee_));
 398  E :    ASSERT_NO_FATAL_FAILURE(CreateCallSiteToBlock(callee_));
 399  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformOnCaller());
 400    :  
 401    :    // A return with an offset is inlined.
 402  E :    EXPECT_THAT(kCodeLeaEsp8, ElementsAreArray(caller_->data(), caller_->size()));
 403  E :  }
 404    :  
 405  E :  TEST_F(InliningTransformTest, DontInlineStackManipulation) {
 406    :    ASSERT_NO_FATAL_FAILURE(
 407  E :        AddBlockFromBuffer(kCodeMovStack, sizeof(kCodeMovStack), &callee_));
 408  E :    ASSERT_NO_FATAL_FAILURE(CreateCallSiteToBlock(callee_));
 409  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformOnCaller());
 410    :  
 411    :    // Taking address of the stack cannot be inlined. (i.e. stack manipulation).
 412  E :    EXPECT_THAT(original_, ElementsAreArray(caller_->data(), caller_->size()));
 413  E :  }
 414    :  
 415  E :  TEST_F(InliningTransformTest, DontInlineIndirectCall) {
 416    :    ASSERT_NO_FATAL_FAILURE(
 417    :        AddBlockFromBuffer(kCodeRetWithOffset,
 418    :                           sizeof(kCodeRetWithOffset),
 419  E :                           &callee_));
 420    :    ASSERT_NO_FATAL_FAILURE(
 421    :        AddBlockFromBuffer(kCodeIndirectCall,
 422    :                           sizeof(kCodeIndirectCall),
 423  E :                           &caller_));
 424  E :    ASSERT_NO_FATAL_FAILURE(SaveCaller());
 425  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformOnCaller());
 426    :  
 427    :    // Taking address of the stack cannot be inlined. (i.e. stack manipulation).
 428  E :    EXPECT_THAT(original_, ElementsAreArray(caller_->data(), caller_->size()));
 429  E :  }
 430    :  
 431  E :  TEST_F(InliningTransformTest, DontInlineNoReturn) {
 432    :    ASSERT_NO_FATAL_FAILURE(
 433  E :        AddBlockFromBuffer(kCodeMov0, sizeof(kCodeMov0), &callee_));
 434  E :    ASSERT_NO_FATAL_FAILURE(CreateCallSiteToBlock(callee_));
 435  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformOnCaller());
 436    :  
 437    :    // No returns found, could not inlined.
 438  E :    EXPECT_THAT(original_, ElementsAreArray(caller_->data(), caller_->size()));
 439  E :  }
 440    :  
 441  E :  TEST_F(InliningTransformTest, DontInlineData) {
 442    :    BlockGraph::Block* data_ =
 443  E :        block_graph_.AddBlock(BlockGraph::DATA_BLOCK, sizeof(kCodeRet0), "d1");
 444  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), data_);
 445  E :    data_->SetData(kCodeRet0, sizeof(kCodeRet0));
 446  E :    ASSERT_NO_FATAL_FAILURE(CreateCallSiteToBlock(data_));
 447  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformOnCaller());
 448    :  
 449    :    // Data block cannot be inlined.
 450  E :    EXPECT_THAT(original_, ElementsAreArray(caller_->data(), caller_->size()));
 451  E :  }
 452    :  
 453  E :  TEST_F(InliningTransformTest, DontInlineForwardControlFlow) {
 454    :    ASSERT_NO_FATAL_FAILURE(
 455  E :        AddBlockFromBuffer(kCodeJump, sizeof(kCodeJump), &callee_));
 456  E :    ASSERT_NO_FATAL_FAILURE(CreateCallSiteToBlock(callee_));
 457  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformOnCaller());
 458    :  
 459  E :    EXPECT_THAT(original_, ElementsAreArray(caller_->data(), caller_->size()));
 460  E :  }
 461    :  
 462  E :  TEST_F(InliningTransformTest, DontInlineSelfControlFlow) {
 463    :    ASSERT_NO_FATAL_FAILURE(
 464  E :        AddBlockFromBuffer(kCodeSelfJump, sizeof(kCodeSelfJump), &callee_));
 465  E :    ASSERT_NO_FATAL_FAILURE(CreateCallSiteToBlock(callee_));
 466  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformOnCaller());
 467    :  
 468  E :    EXPECT_THAT(original_, ElementsAreArray(caller_->data(), caller_->size()));
 469  E :  }
 470    :  
 471  E :  TEST_F(InliningTransformTest, DontInlineBigBlock) {
 472    :    ASSERT_NO_FATAL_FAILURE(
 473  E :        AddBlockFromBuffer(kCodeBig, sizeof(kCodeBig), &callee_));
 474  E :    ASSERT_NO_FATAL_FAILURE(CreateCallSiteToBlock(callee_));
 475  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformOnCaller());
 476    :  
 477    :    // Big block cannot be inlined.
 478  E :    EXPECT_THAT(original_, ElementsAreArray(caller_->data(), caller_->size()));
 479  E :  }
 480    :  
 481  E :  TEST_F(InliningTransformTest, DontInlineCallerPolicy) {
 482    :    ASSERT_NO_FATAL_FAILURE(
 483  E :        AddBlockFromBuffer(kCodeRet0, sizeof(kCodeRet0), &callee_));
 484  E :    ASSERT_NO_FATAL_FAILURE(CreateCallSiteToBlock(callee_));
 485    :  
 486  E :    caller_->set_attributes(BlockGraph::HAS_EXCEPTION_HANDLING);
 487  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformOnCaller());
 488    :  
 489    :    // Cannot inline exception handling. (i.e. policy handling).
 490  E :    EXPECT_THAT(original_, ElementsAreArray(caller_->data(), caller_->size()));
 491  E :  }
 492    :  
 493  E :  TEST_F(InliningTransformTest, DontInlineCalleePolicy) {
 494    :    ASSERT_NO_FATAL_FAILURE(
 495  E :        AddBlockFromBuffer(kCodeRet0, sizeof(kCodeRet0), &callee_));
 496  E :    ASSERT_NO_FATAL_FAILURE(CreateCallSiteToBlock(callee_));
 497    :  
 498  E :    callee_->set_attributes(BlockGraph::HAS_EXCEPTION_HANDLING);
 499  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformOnCaller());
 500    :  
 501    :    // Cannot inline exception handling. (i.e. policy handling).
 502  E :    EXPECT_THAT(original_, ElementsAreArray(caller_->data(), caller_->size()));
 503  E :  }
 504    :  
 505  E :  TEST_F(InliningTransformTest, DontInfiniteLoopOnSelfTrampoline) {
 506    :    ASSERT_NO_FATAL_FAILURE(
 507  E :        AddBlockFromBuffer(kCodeRet, sizeof(kCodeRet), &callee_));
 508    :    ASSERT_NO_FATAL_FAILURE(
 509  E :        CreateCalleeBlock(kRecursiveTrampoline, callee_, &callee_));
 510  E :    ASSERT_NO_FATAL_FAILURE(CreateCallSiteToBlock(callee_));
 511  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformOnCaller());
 512  E :  }
 513    :  
 514  E :  TEST_F(InliningTransformTest, InlineTrampolineToCode) {
 515  E :    BlockGraph::Block* dummy = NULL;
 516    :    ASSERT_NO_FATAL_FAILURE(
 517  E :        AddBlockFromBuffer(kCodeRet42, sizeof(kCodeRet42), &dummy));
 518    :    ASSERT_NO_FATAL_FAILURE(
 519  E :        AddBlockFromBuffer(kCodeRet, sizeof(kCodeRet), &callee_));
 520    :    ASSERT_NO_FATAL_FAILURE(
 521  E :        CreateCalleeBlock(kDirectTrampoline, dummy, &callee_));
 522  E :    ASSERT_NO_FATAL_FAILURE(CreateCallSiteToBlock(callee_));
 523  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformOnCaller());
 524    :  
 525    :    // Validate that the reference from caller is to dummy.
 526  E :    ASSERT_EQ(1U, callee_->references().size());
 527  E :    BlockGraph::Reference reference = callee_->references().begin()->second;
 528  E :    EXPECT_EQ(dummy, reference.referenced());
 529  E :  }
 530    :  
 531  E :  TEST_F(InliningTransformTest, DontInlineTrampolineToData) {
 532    :    BlockGraph::Block* dummy =
 533  E :          block_graph_.AddBlock(BlockGraph::DATA_BLOCK, sizeof(kCodeRet0), "d1");
 534  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), dummy);
 535  E :    dummy->SetData(kCodeRet0, sizeof(kCodeRet0));
 536    :    ASSERT_NO_FATAL_FAILURE(
 537  E :        AddBlockFromBuffer(kCodeRet, sizeof(kCodeRet), &callee_));
 538    :    ASSERT_NO_FATAL_FAILURE(
 539  E :        CreateCalleeBlock(kDirectTrampoline, dummy, &callee_));
 540  E :    ASSERT_NO_FATAL_FAILURE(CreateCallSiteToBlock(callee_));
 541  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformOnCaller());
 542    :  
 543    :    // Validate that the reference from caller is still to callee.
 544  E :    ASSERT_EQ(1U, callee_->references().size());
 545  E :    BlockGraph::Reference reference = callee_->references().begin()->second;
 546  E :    EXPECT_EQ(dummy, reference.referenced());
 547  E :  }
 548    :  
 549  E :  TEST_F(InliningTransformTest, InlineIndirectTrampoline) {
 550    :    ASSERT_NO_FATAL_FAILURE(
 551  E :        AddBlockFromBuffer(kCodeRet, sizeof(kCodeRet), &callee_));
 552    :    ASSERT_NO_FATAL_FAILURE(
 553  E :        CreateCalleeBlock(kIndirectTrampoline, data_, &callee_));
 554  E :    ASSERT_NO_FATAL_FAILURE(CreateCallSiteToBlock(callee_));
 555  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformOnCaller());
 556    :  
 557    :    // Validate that the reference from caller is to |data_|.
 558  E :    ASSERT_EQ(1U, callee_->references().size());
 559  E :    BlockGraph::Reference reference = callee_->references().begin()->second;
 560  E :    EXPECT_EQ(data_, reference.referenced());
 561  E :  }
 562    :  
 563  E :  TEST_F(InliningTransformTest, InlineConstantOnStack) {
 564    :    ASSERT_NO_FATAL_FAILURE(
 565  E :        AddBlockFromBuffer(kStackCst, sizeof(kStackCst), &callee_));
 566  E :    ASSERT_NO_FATAL_FAILURE(CreateCallSiteToBlock(callee_));
 567  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformOnCaller());
 568    :  
 569  E :    EXPECT_THAT(kStackCst, ElementsAreArray(caller_->data(), caller_->size()));
 570  E :  }
 571    :  
 572  E :  TEST_F(InliningTransformTest, InlineOptimizedRet0) {
 573    :    ASSERT_NO_FATAL_FAILURE(
 574    :        AddBlockFromBuffer(kCodeOptimizeRet0, sizeof(kCodeOptimizeRet0),
 575  E :                           &callee_));
 576  E :    ASSERT_NO_FATAL_FAILURE(CreateCallSiteToBlock(callee_));
 577  E :    ASSERT_NO_FATAL_FAILURE(ApplyTransformOnCaller());
 578    :  
 579  E :    EXPECT_THAT(kCodeRet0, ElementsAreArray(caller_->data(), caller_->size()));
 580  E :  }
 581    :  
 582    :  }  // namespace transforms
 583    :  }  // namespace optimize

Coverage information generated Wed Dec 11 11:34:16 2013.