LCOV - code coverage report
Current view: top level - test/cctest - test-unwinder.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 287 287 100.0 %
Date: 2019-04-17 Functions: 18 18 100.0 %

          Line data    Source code
       1             : // Copyright 2018 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "include/v8.h"
       6             : 
       7             : #include "src/api-inl.h"
       8             : #include "src/builtins/builtins.h"
       9             : #include "src/heap/spaces.h"
      10             : #include "src/isolate.h"
      11             : #include "src/objects/code-inl.h"
      12             : #include "test/cctest/cctest.h"
      13             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : namespace test_unwinder {
      17             : 
      18             : static void* unlimited_stack_base = std::numeric_limits<void*>::max();
      19             : 
      20       26644 : TEST(Unwind_BadState_Fail) {
      21           5 :   UnwindState unwind_state;  // Fields are intialized to nullptr.
      22             :   RegisterState register_state;
      23             : 
      24           5 :   bool unwound = v8::Unwinder::TryUnwindV8Frames(unwind_state, &register_state,
      25           5 :                                                  unlimited_stack_base);
      26           5 :   CHECK(!unwound);
      27             :   // The register state should not change when unwinding fails.
      28           5 :   CHECK_NULL(register_state.fp);
      29           5 :   CHECK_NULL(register_state.sp);
      30           5 :   CHECK_NULL(register_state.pc);
      31           5 : }
      32             : 
      33       26644 : TEST(Unwind_BuiltinPCInMiddle_Success) {
      34           5 :   LocalContext env;
      35           5 :   v8::Isolate* isolate = env->GetIsolate();
      36             :   Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
      37             : 
      38           5 :   UnwindState unwind_state = isolate->GetUnwindState();
      39             :   RegisterState register_state;
      40             : 
      41             :   uintptr_t stack[3];
      42             :   void* stack_base = stack + arraysize(stack);
      43           5 :   stack[0] = reinterpret_cast<uintptr_t>(stack + 2);  // saved FP (rbp).
      44           5 :   stack[1] = 202;  // Return address into C++ code.
      45           5 :   stack[2] = 303;  // The SP points here in the caller's frame.
      46             : 
      47           5 :   register_state.sp = stack;
      48           5 :   register_state.fp = stack;
      49             : 
      50             :   // Put the current PC inside of a valid builtin.
      51           5 :   Code builtin = i_isolate->builtins()->builtin(Builtins::kStringEqual);
      52             :   const uintptr_t offset = 40;
      53           5 :   CHECK_LT(offset, builtin->InstructionSize());
      54             :   register_state.pc =
      55           5 :       reinterpret_cast<void*>(builtin->InstructionStart() + offset);
      56             : 
      57             :   bool unwound = v8::Unwinder::TryUnwindV8Frames(unwind_state, &register_state,
      58           5 :                                                  stack_base);
      59           5 :   CHECK(unwound);
      60           5 :   CHECK_EQ(reinterpret_cast<void*>(stack + 2), register_state.fp);
      61           5 :   CHECK_EQ(reinterpret_cast<void*>(stack + 2), register_state.sp);
      62           5 :   CHECK_EQ(reinterpret_cast<void*>(202), register_state.pc);
      63           5 : }
      64             : 
      65             : // The unwinder should be able to unwind even if we haven't properly set up the
      66             : // current frame, as long as there is another JS frame underneath us (i.e. as
      67             : // long as the PC isn't in JSEntry). This test puts the PC at the start
      68             : // of a JS builtin and creates a fake JSEntry frame before it on the stack. The
      69             : // unwinder should be able to unwind to the C++ frame before the JSEntry frame.
      70       26644 : TEST(Unwind_BuiltinPCAtStart_Success) {
      71           5 :   LocalContext env;
      72           5 :   v8::Isolate* isolate = env->GetIsolate();
      73             :   Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
      74             : 
      75           5 :   UnwindState unwind_state = isolate->GetUnwindState();
      76             :   RegisterState register_state;
      77             : 
      78             :   const size_t code_length = 40;
      79           5 :   uintptr_t code[code_length] = {0};
      80           5 :   unwind_state.code_range.start = code;
      81           5 :   unwind_state.code_range.length_in_bytes = code_length * sizeof(uintptr_t);
      82             : 
      83             :   uintptr_t stack[6];
      84             :   void* stack_base = stack + arraysize(stack);
      85           5 :   stack[0] = 101;
      86             :   // Return address into JS code. It doesn't matter that this is not actually in
      87             :   // JSEntry, because we only check that for the top frame.
      88           5 :   stack[1] = reinterpret_cast<uintptr_t>(code + 10);
      89           5 :   stack[2] = reinterpret_cast<uintptr_t>(stack + 5);  // saved FP (rbp).
      90           5 :   stack[3] = 303;  // Return address into C++ code.
      91           5 :   stack[4] = 404;
      92           5 :   stack[5] = 505;
      93             : 
      94           5 :   register_state.sp = stack;
      95           5 :   register_state.fp = stack + 2;  // FP to the JSEntry frame.
      96             : 
      97             :   // Put the current PC at the start of a valid builtin, so that we are setting
      98             :   // up the frame.
      99           5 :   Code builtin = i_isolate->builtins()->builtin(Builtins::kStringEqual);
     100           5 :   register_state.pc = reinterpret_cast<void*>(builtin->InstructionStart());
     101             : 
     102             :   bool unwound = v8::Unwinder::TryUnwindV8Frames(unwind_state, &register_state,
     103           5 :                                                  stack_base);
     104             : 
     105           5 :   CHECK(unwound);
     106           5 :   CHECK_EQ(reinterpret_cast<void*>(stack + 5), register_state.fp);
     107           5 :   CHECK_EQ(reinterpret_cast<void*>(stack + 4), register_state.sp);
     108           5 :   CHECK_EQ(reinterpret_cast<void*>(303), register_state.pc);
     109           5 : }
     110             : 
     111             : const char* foo_source = R"(
     112             :   function foo(a, b) {
     113             :     let x = a * b;
     114             :     let y = x ^ b;
     115             :     let z = y / a;
     116             :     return x + y - z;
     117             :   }
     118             :   foo(1, 2);
     119             :   foo(1, 2);
     120             :   %OptimizeFunctionOnNextCall(foo);
     121             :   foo(1, 2);
     122             : )";
     123             : 
     124             : // Check that we can unwind when the pc is within an optimized code object on
     125             : // the V8 heap.
     126       26644 : TEST(Unwind_CodeObjectPCInMiddle_Success) {
     127           5 :   FLAG_allow_natives_syntax = true;
     128           4 :   LocalContext env;
     129           5 :   v8::Isolate* isolate = env->GetIsolate();
     130             :   Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
     131             :   HandleScope scope(i_isolate);
     132             : 
     133           5 :   UnwindState unwind_state = isolate->GetUnwindState();
     134             :   RegisterState register_state;
     135             : 
     136             :   uintptr_t stack[3];
     137             :   void* stack_base = stack + arraysize(stack);
     138           5 :   stack[0] = reinterpret_cast<uintptr_t>(stack + 2);  // saved FP (rbp).
     139           5 :   stack[1] = 202;  // Return address into C++ code.
     140           5 :   stack[2] = 303;  // The SP points here in the caller's frame.
     141             : 
     142           5 :   register_state.sp = stack;
     143           5 :   register_state.fp = stack;
     144             : 
     145             :   // Create an on-heap code object. Make sure we run the function so that it is
     146             :   // compiled and not just marked for lazy compilation.
     147           5 :   CompileRun(foo_source);
     148             :   v8::Local<v8::Function> local_foo = v8::Local<v8::Function>::Cast(
     149          20 :       env.local()->Global()->Get(env.local(), v8_str("foo")).ToLocalChecked());
     150             :   Handle<JSFunction> foo =
     151             :       Handle<JSFunction>::cast(v8::Utils::OpenHandle(*local_foo));
     152             : 
     153             :   // Put the current PC inside of the created code object.
     154           5 :   AbstractCode abstract_code = foo->abstract_code();
     155             :   // We don't produce optimized code when run with --no-opt.
     156           5 :   if (!abstract_code->IsCode() && FLAG_opt == false) return;
     157           4 :   CHECK(abstract_code->IsCode());
     158             : 
     159           4 :   Code code = abstract_code->GetCode();
     160             :   // We don't want the offset too early or it could be the `push rbp`
     161             :   // instruction (which is not at the start of generated code, because the lazy
     162             :   // deopt check happens before frame setup).
     163           4 :   const uintptr_t offset = code->InstructionSize() - 20;
     164           4 :   CHECK_LT(offset, code->InstructionSize());
     165           4 :   Address pc = code->InstructionStart() + offset;
     166           4 :   register_state.pc = reinterpret_cast<void*>(pc);
     167             : 
     168             :   // Check that the created code is within the code range that we get from the
     169             :   // API.
     170           4 :   Address start = reinterpret_cast<Address>(unwind_state.code_range.start);
     171           4 :   CHECK(pc >= start && pc < start + unwind_state.code_range.length_in_bytes);
     172             : 
     173             :   bool unwound = v8::Unwinder::TryUnwindV8Frames(unwind_state, &register_state,
     174           4 :                                                  stack_base);
     175           4 :   CHECK(unwound);
     176           4 :   CHECK_EQ(reinterpret_cast<void*>(stack + 2), register_state.fp);
     177           4 :   CHECK_EQ(reinterpret_cast<void*>(stack + 2), register_state.sp);
     178           4 :   CHECK_EQ(reinterpret_cast<void*>(202), register_state.pc);
     179             : }
     180             : 
     181             : // If the PC is within JSEntry but we haven't set up the frame yet, then we
     182             : // cannot unwind.
     183       26644 : TEST(Unwind_JSEntryBeforeFrame_Fail) {
     184           5 :   LocalContext env;
     185           5 :   v8::Isolate* isolate = env->GetIsolate();
     186             : 
     187           5 :   UnwindState unwind_state = isolate->GetUnwindState();
     188             :   RegisterState register_state;
     189             : 
     190             :   const size_t code_length = 40;
     191           5 :   uintptr_t code[code_length] = {0};
     192           5 :   unwind_state.code_range.start = code;
     193           5 :   unwind_state.code_range.length_in_bytes = code_length * sizeof(uintptr_t);
     194             : 
     195             :   // Pretend that it takes 5 instructions to set up the frame in JSEntry.
     196           5 :   unwind_state.js_entry_stub.code.start = code + 10;
     197           5 :   unwind_state.js_entry_stub.code.length_in_bytes = 10 * sizeof(uintptr_t);
     198             : 
     199             :   uintptr_t stack[10];
     200             :   void* stack_base = stack + arraysize(stack);
     201           5 :   stack[0] = 101;
     202           5 :   stack[1] = 111;
     203           5 :   stack[2] = 121;
     204           5 :   stack[3] = 131;
     205           5 :   stack[4] = 141;
     206           5 :   stack[5] = 151;
     207           5 :   stack[6] = 100;  // Return address into C++ code.
     208           5 :   stack[7] = 303;  // The SP points here in the caller's frame.
     209           5 :   stack[8] = 404;
     210           5 :   stack[9] = 505;
     211             : 
     212           5 :   register_state.sp = stack + 5;
     213           5 :   register_state.fp = stack + 9;
     214             : 
     215             :   // Put the current PC inside of JSEntry, before the frame is set up.
     216           5 :   register_state.pc = code + 12;
     217             :   bool unwound = v8::Unwinder::TryUnwindV8Frames(unwind_state, &register_state,
     218           5 :                                                  stack_base);
     219           5 :   CHECK(!unwound);
     220             :   // The register state should not change when unwinding fails.
     221           5 :   CHECK_EQ(reinterpret_cast<void*>(stack + 9), register_state.fp);
     222           5 :   CHECK_EQ(reinterpret_cast<void*>(stack + 5), register_state.sp);
     223           5 :   CHECK_EQ(code + 12, register_state.pc);
     224             : 
     225             :   // Change the PC to a few instructions later, after the frame is set up.
     226           5 :   register_state.pc = code + 16;
     227             :   unwound = v8::Unwinder::TryUnwindV8Frames(unwind_state, &register_state,
     228           5 :                                             stack_base);
     229             :   // TODO(petermarshall): More precisely check position within JSEntry rather
     230             :   // than just assuming the frame is unreadable.
     231           5 :   CHECK(!unwound);
     232             :   // The register state should not change when unwinding fails.
     233           5 :   CHECK_EQ(reinterpret_cast<void*>(stack + 9), register_state.fp);
     234           5 :   CHECK_EQ(reinterpret_cast<void*>(stack + 5), register_state.sp);
     235           5 :   CHECK_EQ(code + 16, register_state.pc);
     236           5 : }
     237             : 
     238       26644 : TEST(Unwind_OneJSFrame_Success) {
     239           5 :   LocalContext env;
     240           5 :   v8::Isolate* isolate = env->GetIsolate();
     241             : 
     242           5 :   UnwindState unwind_state = isolate->GetUnwindState();
     243             :   RegisterState register_state;
     244             : 
     245             :   // Use a fake code range so that we can initialize it to 0s.
     246             :   const size_t code_length = 40;
     247           5 :   uintptr_t code[code_length] = {0};
     248           5 :   unwind_state.code_range.start = code;
     249           5 :   unwind_state.code_range.length_in_bytes = code_length * sizeof(uintptr_t);
     250             : 
     251             :   // Our fake stack has two frames - one C++ frame and one JS frame (on top).
     252             :   // The stack grows from high addresses to low addresses.
     253             :   uintptr_t stack[10];
     254             :   void* stack_base = stack + arraysize(stack);
     255           5 :   stack[0] = 101;
     256           5 :   stack[1] = 111;
     257           5 :   stack[2] = 121;
     258           5 :   stack[3] = 131;
     259           5 :   stack[4] = 141;
     260           5 :   stack[5] = reinterpret_cast<uintptr_t>(stack + 9);  // saved FP (rbp).
     261           5 :   stack[6] = 100;  // Return address into C++ code.
     262           5 :   stack[7] = 303;  // The SP points here in the caller's frame.
     263           5 :   stack[8] = 404;
     264           5 :   stack[9] = 505;
     265             : 
     266           5 :   register_state.sp = stack;
     267           5 :   register_state.fp = stack + 5;
     268             : 
     269             :   // Put the current PC inside of the code range so it looks valid.
     270           5 :   register_state.pc = code + 30;
     271             : 
     272             :   bool unwound = v8::Unwinder::TryUnwindV8Frames(unwind_state, &register_state,
     273           5 :                                                  stack_base);
     274             : 
     275           5 :   CHECK(unwound);
     276           5 :   CHECK_EQ(reinterpret_cast<void*>(stack + 9), register_state.fp);
     277           5 :   CHECK_EQ(reinterpret_cast<void*>(stack + 7), register_state.sp);
     278           5 :   CHECK_EQ(reinterpret_cast<void*>(100), register_state.pc);
     279           5 : }
     280             : 
     281             : // Creates a fake stack with two JS frames on top of a C++ frame and checks that
     282             : // the unwinder correctly unwinds past the JS frames and returns the C++ frame's
     283             : // details.
     284       26644 : TEST(Unwind_TwoJSFrames_Success) {
     285           5 :   LocalContext env;
     286           5 :   v8::Isolate* isolate = env->GetIsolate();
     287             : 
     288           5 :   UnwindState unwind_state = isolate->GetUnwindState();
     289             :   RegisterState register_state;
     290             : 
     291             :   // Use a fake code range so that we can initialize it to 0s.
     292             :   const size_t code_length = 40;
     293           5 :   uintptr_t code[code_length] = {0};
     294           5 :   unwind_state.code_range.start = code;
     295           5 :   unwind_state.code_range.length_in_bytes = code_length * sizeof(uintptr_t);
     296             : 
     297             :   // Our fake stack has three frames - one C++ frame and two JS frames (on top).
     298             :   // The stack grows from high addresses to low addresses.
     299             :   uintptr_t stack[10];
     300             :   void* stack_base = stack + arraysize(stack);
     301           5 :   stack[0] = 101;
     302           5 :   stack[1] = 111;
     303           5 :   stack[2] = reinterpret_cast<uintptr_t>(stack + 5);  // saved FP (rbp).
     304             :   // The fake return address is in the JS code range.
     305           5 :   stack[3] = reinterpret_cast<uintptr_t>(code + 10);
     306           5 :   stack[4] = 141;
     307           5 :   stack[5] = reinterpret_cast<uintptr_t>(stack + 9);  // saved FP (rbp).
     308           5 :   stack[6] = 100;  // Return address into C++ code.
     309           5 :   stack[7] = 303;  // The SP points here in the caller's frame.
     310           5 :   stack[8] = 404;
     311           5 :   stack[9] = 505;
     312             : 
     313           5 :   register_state.sp = stack;
     314           5 :   register_state.fp = stack + 2;
     315             : 
     316             :   // Put the current PC inside of the code range so it looks valid.
     317           5 :   register_state.pc = code + 30;
     318             : 
     319             :   bool unwound = v8::Unwinder::TryUnwindV8Frames(unwind_state, &register_state,
     320           5 :                                                  stack_base);
     321             : 
     322           5 :   CHECK(unwound);
     323           5 :   CHECK_EQ(reinterpret_cast<void*>(stack + 9), register_state.fp);
     324           5 :   CHECK_EQ(reinterpret_cast<void*>(stack + 7), register_state.sp);
     325           5 :   CHECK_EQ(reinterpret_cast<void*>(100), register_state.pc);
     326           5 : }
     327             : 
     328             : // If the PC is in JSEntry then the frame might not be set up correctly, meaning
     329             : // we can't unwind the stack properly.
     330       26644 : TEST(Unwind_JSEntry_Fail) {
     331           5 :   LocalContext env;
     332           5 :   v8::Isolate* isolate = env->GetIsolate();
     333             :   Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
     334             : 
     335           5 :   UnwindState unwind_state = isolate->GetUnwindState();
     336             :   RegisterState register_state;
     337             : 
     338           5 :   Code js_entry = i_isolate->heap()->builtin(Builtins::kJSEntry);
     339           5 :   byte* start = reinterpret_cast<byte*>(js_entry->InstructionStart());
     340           5 :   register_state.pc = start + 10;
     341             : 
     342           5 :   bool unwound = v8::Unwinder::TryUnwindV8Frames(unwind_state, &register_state,
     343           5 :                                                  unlimited_stack_base);
     344           5 :   CHECK(!unwound);
     345             :   // The register state should not change when unwinding fails.
     346           5 :   CHECK_NULL(register_state.fp);
     347           5 :   CHECK_NULL(register_state.sp);
     348           5 :   CHECK_EQ(start + 10, register_state.pc);
     349           5 : }
     350             : 
     351       26644 : TEST(Unwind_StackBounds_Basic) {
     352           5 :   LocalContext env;
     353           5 :   v8::Isolate* isolate = env->GetIsolate();
     354             : 
     355           5 :   UnwindState unwind_state = isolate->GetUnwindState();
     356             :   RegisterState register_state;
     357             : 
     358             :   const size_t code_length = 10;
     359           5 :   uintptr_t code[code_length] = {0};
     360           5 :   unwind_state.code_range.start = code;
     361           5 :   unwind_state.code_range.length_in_bytes = code_length * sizeof(uintptr_t);
     362             : 
     363             :   uintptr_t stack[3];
     364           5 :   stack[0] = reinterpret_cast<uintptr_t>(stack + 2);  // saved FP (rbp).
     365           5 :   stack[1] = 202;  // Return address into C++ code.
     366           5 :   stack[2] = 303;  // The SP points here in the caller's frame.
     367             : 
     368           5 :   register_state.sp = stack;
     369           5 :   register_state.fp = stack;
     370           5 :   register_state.pc = code;
     371             : 
     372             :   void* wrong_stack_base = reinterpret_cast<void*>(
     373           5 :       reinterpret_cast<uintptr_t>(stack) - sizeof(uintptr_t));
     374             :   bool unwound = v8::Unwinder::TryUnwindV8Frames(unwind_state, &register_state,
     375           5 :                                                  wrong_stack_base);
     376           5 :   CHECK(!unwound);
     377             : 
     378             :   // Correct the stack base and unwinding should succeed.
     379             :   void* correct_stack_base = stack + arraysize(stack);
     380             :   unwound = v8::Unwinder::TryUnwindV8Frames(unwind_state, &register_state,
     381           5 :                                             correct_stack_base);
     382           5 :   CHECK(unwound);
     383           5 : }
     384             : 
     385       26644 : TEST(Unwind_StackBounds_WithUnwinding) {
     386           5 :   LocalContext env;
     387           5 :   v8::Isolate* isolate = env->GetIsolate();
     388             : 
     389           5 :   UnwindState unwind_state = isolate->GetUnwindState();
     390             :   RegisterState register_state;
     391             : 
     392             :   // Use a fake code range so that we can initialize it to 0s.
     393             :   const size_t code_length = 40;
     394           5 :   uintptr_t code[code_length] = {0};
     395           5 :   unwind_state.code_range.start = code;
     396           5 :   unwind_state.code_range.length_in_bytes = code_length * sizeof(uintptr_t);
     397             : 
     398             :   // Our fake stack has two frames - one C++ frame and one JS frame (on top).
     399             :   // The stack grows from high addresses to low addresses.
     400             :   uintptr_t stack[11];
     401             :   void* stack_base = stack + arraysize(stack);
     402           5 :   stack[0] = 101;
     403           5 :   stack[1] = 111;
     404           5 :   stack[2] = 121;
     405           5 :   stack[3] = 131;
     406           5 :   stack[4] = 141;
     407           5 :   stack[5] = reinterpret_cast<uintptr_t>(stack + 9);  // saved FP (rbp).
     408           5 :   stack[6] = reinterpret_cast<uintptr_t>(code + 20);  // JS code.
     409           5 :   stack[7] = 303;  // The SP points here in the caller's frame.
     410           5 :   stack[8] = 404;
     411           5 :   stack[9] = reinterpret_cast<uintptr_t>(stack) +
     412           5 :              (12 * sizeof(uintptr_t));                 // saved FP (OOB).
     413           5 :   stack[10] = reinterpret_cast<uintptr_t>(code + 20);  // JS code.
     414             : 
     415           5 :   register_state.sp = stack;
     416           5 :   register_state.fp = stack + 5;
     417             : 
     418             :   // Put the current PC inside of the code range so it looks valid.
     419           5 :   register_state.pc = code + 30;
     420             : 
     421             :   // Unwind will fail because stack[9] FP points outside of the stack.
     422             :   bool unwound = v8::Unwinder::TryUnwindV8Frames(unwind_state, &register_state,
     423           5 :                                                  stack_base);
     424           5 :   CHECK(!unwound);
     425             : 
     426             :   // Change the return address so that it is not in range. We will not range
     427             :   // check the stack[9] FP value because we have finished unwinding and the
     428             :   // contents of rbp does not necessarily have to be the FP in this case.
     429           5 :   stack[10] = 202;
     430             :   unwound = v8::Unwinder::TryUnwindV8Frames(unwind_state, &register_state,
     431           5 :                                             stack_base);
     432           5 :   CHECK(unwound);
     433           5 : }
     434             : 
     435       26644 : TEST(PCIsInV8_BadState_Fail) {
     436           5 :   UnwindState unwind_state;
     437             :   void* pc = nullptr;
     438             : 
     439           5 :   CHECK(!v8::Unwinder::PCIsInV8(unwind_state, pc));
     440           5 : }
     441             : 
     442       26644 : TEST(PCIsInV8_ValidStateNullPC_Fail) {
     443           5 :   LocalContext env;
     444           5 :   v8::Isolate* isolate = env->GetIsolate();
     445             : 
     446           5 :   UnwindState unwind_state = isolate->GetUnwindState();
     447             :   void* pc = nullptr;
     448             : 
     449           5 :   CHECK(!v8::Unwinder::PCIsInV8(unwind_state, pc));
     450           5 : }
     451             : 
     452          10 : void TestRangeBoundaries(const UnwindState& unwind_state, byte* range_start,
     453             :                          size_t range_length) {
     454          10 :   void* pc = range_start - 1;
     455          10 :   CHECK(!v8::Unwinder::PCIsInV8(unwind_state, pc));
     456             :   pc = range_start;
     457          10 :   CHECK(v8::Unwinder::PCIsInV8(unwind_state, pc));
     458          10 :   pc = range_start + 1;
     459          10 :   CHECK(v8::Unwinder::PCIsInV8(unwind_state, pc));
     460          10 :   pc = range_start + range_length - 1;
     461          10 :   CHECK(v8::Unwinder::PCIsInV8(unwind_state, pc));
     462          10 :   pc = range_start + range_length;
     463          10 :   CHECK(!v8::Unwinder::PCIsInV8(unwind_state, pc));
     464          10 :   pc = range_start + range_length + 1;
     465          10 :   CHECK(!v8::Unwinder::PCIsInV8(unwind_state, pc));
     466          10 : }
     467             : 
     468       26644 : TEST(PCIsInV8_InCodeOrEmbeddedRange) {
     469           5 :   LocalContext env;
     470           5 :   v8::Isolate* isolate = env->GetIsolate();
     471             : 
     472           5 :   UnwindState unwind_state = isolate->GetUnwindState();
     473             : 
     474             :   byte* code_range_start = const_cast<byte*>(
     475           5 :       reinterpret_cast<const byte*>(unwind_state.code_range.start));
     476           5 :   size_t code_range_length = unwind_state.code_range.length_in_bytes;
     477           5 :   TestRangeBoundaries(unwind_state, code_range_start, code_range_length);
     478             : 
     479             :   byte* embedded_range_start = const_cast<byte*>(
     480           5 :       reinterpret_cast<const byte*>(unwind_state.embedded_code_range.start));
     481             :   size_t embedded_range_length =
     482           5 :       unwind_state.embedded_code_range.length_in_bytes;
     483             :   TestRangeBoundaries(unwind_state, embedded_range_start,
     484           5 :                       embedded_range_length);
     485           5 : }
     486             : 
     487             : // PCIsInV8 doesn't check if the PC is in JSEntry directly. It's assumed that
     488             : // the CodeRange or EmbeddedCodeRange contain JSEntry.
     489       26644 : TEST(PCIsInV8_InJSEntryRange) {
     490           5 :   LocalContext env;
     491           5 :   v8::Isolate* isolate = env->GetIsolate();
     492             :   Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
     493             : 
     494           5 :   UnwindState unwind_state = isolate->GetUnwindState();
     495             : 
     496           5 :   Code js_entry = i_isolate->heap()->builtin(Builtins::kJSEntry);
     497           5 :   byte* start = reinterpret_cast<byte*>(js_entry->InstructionStart());
     498           5 :   size_t length = js_entry->InstructionSize();
     499             : 
     500             :   void* pc = start;
     501           5 :   CHECK(v8::Unwinder::PCIsInV8(unwind_state, pc));
     502           5 :   pc = start + 1;
     503           5 :   CHECK(v8::Unwinder::PCIsInV8(unwind_state, pc));
     504           5 :   pc = start + length - 1;
     505           5 :   CHECK(v8::Unwinder::PCIsInV8(unwind_state, pc));
     506           5 : }
     507             : 
     508             : // Large code objects can be allocated in large object space. Check that this is
     509             : // inside the CodeRange.
     510       26644 : TEST(PCIsInV8_LargeCodeObject) {
     511           5 :   FLAG_allow_natives_syntax = true;
     512           5 :   LocalContext env;
     513           5 :   v8::Isolate* isolate = env->GetIsolate();
     514             :   Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
     515             :   HandleScope scope(i_isolate);
     516             : 
     517           5 :   UnwindState unwind_state = isolate->GetUnwindState();
     518             : 
     519             :   // Create a big function that ends up in CODE_LO_SPACE.
     520             :   const int instruction_size = Page::kPageSize + 1;
     521             :   STATIC_ASSERT(instruction_size > kMaxRegularHeapObjectSize);
     522           5 :   std::unique_ptr<byte[]> instructions(new byte[instruction_size]);
     523             : 
     524           5 :   CodeDesc desc;
     525           5 :   desc.buffer = instructions.get();
     526           5 :   desc.buffer_size = instruction_size;
     527           5 :   desc.instr_size = instruction_size;
     528             :   desc.reloc_size = 0;
     529             :   desc.constant_pool_size = 0;
     530             :   desc.unwinding_info = nullptr;
     531             :   desc.unwinding_info_size = 0;
     532             :   desc.origin = nullptr;
     533             :   Handle<Object> self_ref;
     534             :   Handle<Code> foo_code =
     535           5 :       i_isolate->factory()->NewCode(desc, Code::WASM_FUNCTION, self_ref);
     536             : 
     537          10 :   CHECK(i_isolate->heap()->InSpace(*foo_code, CODE_LO_SPACE));
     538          10 :   byte* start = reinterpret_cast<byte*>(foo_code->InstructionStart());
     539             : 
     540             :   void* pc = start;
     541           5 :   CHECK(v8::Unwinder::PCIsInV8(unwind_state, pc));
     542           5 : }
     543             : 
     544             : }  // namespace test_unwinder
     545             : }  // namespace internal
     546       79917 : }  // namespace v8

Generated by: LCOV version 1.10