runtime-test.cc 36 KB
Newer Older
1 2 3 4
// Copyright 2014 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.

5
#include "src/runtime/runtime-utils.h"
6

7
#include <memory>
8
#include <sstream>
9

10
#include "src/api-inl.h"
11
#include "src/arguments.h"
12
#include "src/assembler-inl.h"
13
#include "src/compiler-dispatcher/optimizing-compile-dispatcher.h"
14
#include "src/compiler.h"
15
#include "src/deoptimizer.h"
16
#include "src/frames-inl.h"
17
#include "src/isolate-inl.h"
18
#include "src/runtime-profiler.h"
19
#include "src/snapshot/natives.h"
20
#include "src/trap-handler/trap-handler.h"
21
#include "src/wasm/memory-tracing.h"
22
#include "src/wasm/module-compiler.h"
23
#include "src/wasm/wasm-engine.h"
24
#include "src/wasm/wasm-module.h"
25
#include "src/wasm/wasm-objects-inl.h"
26
#include "src/wasm/wasm-serialization.h"
27

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
namespace {
struct WasmCompileControls {
  uint32_t MaxWasmBufferSize = std::numeric_limits<uint32_t>::max();
  bool AllowAnySizeForAsync = true;
};

// We need per-isolate controls, because we sometimes run tests in multiple
// isolates
// concurrently.
// To avoid upsetting the static initializer count, we lazy initialize this.
v8::base::LazyInstance<std::map<v8::Isolate*, WasmCompileControls>>::type
    g_PerIsolateWasmControls = LAZY_INSTANCE_INITIALIZER;

bool IsWasmCompileAllowed(v8::Isolate* isolate, v8::Local<v8::Value> value,
                          bool is_async) {
  DCHECK_GT(g_PerIsolateWasmControls.Get().count(isolate), 0);
  const WasmCompileControls& ctrls = g_PerIsolateWasmControls.Get().at(isolate);
  return (is_async && ctrls.AllowAnySizeForAsync) ||
46 47 48
         (value->IsArrayBuffer() &&
          v8::Local<v8::ArrayBuffer>::Cast(value)->ByteLength() <=
              ctrls.MaxWasmBufferSize);
49 50 51 52 53
}

// Use the compile controls for instantiation, too
bool IsWasmInstantiateAllowed(v8::Isolate* isolate,
                              v8::Local<v8::Value> module_or_bytes,
54
                              bool is_async) {
55 56 57 58 59 60 61 62
  DCHECK_GT(g_PerIsolateWasmControls.Get().count(isolate), 0);
  const WasmCompileControls& ctrls = g_PerIsolateWasmControls.Get().at(isolate);
  if (is_async && ctrls.AllowAnySizeForAsync) return true;
  if (!module_or_bytes->IsWebAssemblyCompiledModule()) {
    return IsWasmCompileAllowed(isolate, module_or_bytes, is_async);
  }
  v8::Local<v8::WasmCompiledModule> module =
      v8::Local<v8::WasmCompiledModule>::Cast(module_or_bytes);
63
  return static_cast<uint32_t>(module->GetWasmWireBytesRef().size) <=
64 65
         ctrls.MaxWasmBufferSize;
}
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91

v8::Local<v8::Value> NewRangeException(v8::Isolate* isolate,
                                       const char* message) {
  return v8::Exception::RangeError(
      v8::String::NewFromOneByte(isolate,
                                 reinterpret_cast<const uint8_t*>(message),
                                 v8::NewStringType::kNormal)
          .ToLocalChecked());
}

void ThrowRangeException(v8::Isolate* isolate, const char* message) {
  isolate->ThrowException(NewRangeException(isolate, message));
}

bool WasmModuleOverride(const v8::FunctionCallbackInfo<v8::Value>& args) {
  if (IsWasmCompileAllowed(args.GetIsolate(), args[0], false)) return false;
  ThrowRangeException(args.GetIsolate(), "Sync compile not allowed");
  return true;
}

bool WasmInstanceOverride(const v8::FunctionCallbackInfo<v8::Value>& args) {
  if (IsWasmInstantiateAllowed(args.GetIsolate(), args[0], false)) return false;
  ThrowRangeException(args.GetIsolate(), "Sync instantiate not allowed");
  return true;
}

92 93
}  // namespace

94 95 96
namespace v8 {
namespace internal {

97 98
RUNTIME_FUNCTION(Runtime_ConstructDouble) {
  HandleScope scope(isolate);
99
  DCHECK_EQ(2, args.length());
100 101 102 103 104 105
  CONVERT_NUMBER_CHECKED(uint32_t, hi, Uint32, args[0]);
  CONVERT_NUMBER_CHECKED(uint32_t, lo, Uint32, args[1]);
  uint64_t result = (static_cast<uint64_t>(hi) << 32) | lo;
  return *isolate->factory()->NewNumber(uint64_to_double(result));
}

106 107 108 109 110 111 112 113 114 115 116 117 118 119
RUNTIME_FUNCTION(Runtime_ConstructConsString) {
  HandleScope scope(isolate);
  DCHECK_EQ(2, args.length());
  CONVERT_ARG_HANDLE_CHECKED(String, left, 0);
  CONVERT_ARG_HANDLE_CHECKED(String, right, 1);

  CHECK(left->IsOneByteRepresentation());
  CHECK(right->IsOneByteRepresentation());

  const bool kIsOneByte = true;
  const int length = left->length() + right->length();
  return *isolate->factory()->NewConsString(left, right, length, kIsOneByte);
}

120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
RUNTIME_FUNCTION(Runtime_ConstructSlicedString) {
  HandleScope scope(isolate);
  DCHECK_EQ(2, args.length());
  CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
  CONVERT_ARG_HANDLE_CHECKED(Smi, index, 1);

  CHECK(string->IsOneByteRepresentation());
  CHECK_LT(index->value(), string->length());

  Handle<String> sliced_string = isolate->factory()->NewSubString(
      string, index->value(), string->length());
  CHECK(sliced_string->IsSlicedString());
  return *sliced_string;
}

135 136
RUNTIME_FUNCTION(Runtime_DeoptimizeFunction) {
  HandleScope scope(isolate);
137
  DCHECK_EQ(1, args.length());
138 139 140 141 142

  // This function is used by fuzzers to get coverage in compiler.
  // Ignore calls on non-function objects to avoid runtime errors.
  CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0);
  if (!function_object->IsJSFunction()) {
143
    return ReadOnlyRoots(isolate).undefined_value();
144 145 146
  }
  Handle<JSFunction> function = Handle<JSFunction>::cast(function_object);

147
  // If the function is not optimized, just return.
148
  if (!function->IsOptimized()) return ReadOnlyRoots(isolate).undefined_value();
149 150 151

  Deoptimizer::DeoptimizeFunction(*function);

152
  return ReadOnlyRoots(isolate).undefined_value();
153 154 155
}


156 157
RUNTIME_FUNCTION(Runtime_DeoptimizeNow) {
  HandleScope scope(isolate);
158
  DCHECK_EQ(0, args.length());
159 160 161

  Handle<JSFunction> function;

162
  // Find the JavaScript function on the top of the stack.
163
  JavaScriptFrameIterator it(isolate);
164
  if (!it.done()) function = handle(it.frame()->function(), isolate);
165
  if (function.is_null()) return ReadOnlyRoots(isolate).undefined_value();
166

167
  // If the function is not optimized, just return.
168
  if (!function->IsOptimized()) return ReadOnlyRoots(isolate).undefined_value();
169 170 171

  Deoptimizer::DeoptimizeFunction(*function);

172
  return ReadOnlyRoots(isolate).undefined_value();
173 174 175
}


176 177
RUNTIME_FUNCTION(Runtime_RunningInSimulator) {
  SealHandleScope shs(isolate);
178
  DCHECK_EQ(0, args.length());
179
#if defined(USE_SIMULATOR)
180
  return ReadOnlyRoots(isolate).true_value();
181
#else
182
  return ReadOnlyRoots(isolate).false_value();
183 184 185 186 187 188
#endif
}


RUNTIME_FUNCTION(Runtime_IsConcurrentRecompilationSupported) {
  SealHandleScope shs(isolate);
189
  DCHECK_EQ(0, args.length());
190 191 192 193 194 195
  return isolate->heap()->ToBoolean(
      isolate->concurrent_recompilation_enabled());
}

RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) {
  HandleScope scope(isolate);
196 197 198

  // This function is used by fuzzers, ignore calls with bogus arguments count.
  if (args.length() != 1 && args.length() != 2) {
199
    return ReadOnlyRoots(isolate).undefined_value();
200
  }
201 202 203 204 205

  // This function is used by fuzzers to get coverage for optimizations
  // in compiler. Ignore calls on non-function objects to avoid runtime errors.
  CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0);
  if (!function_object->IsJSFunction()) {
206
    return ReadOnlyRoots(isolate).undefined_value();
207 208 209
  }
  Handle<JSFunction> function = Handle<JSFunction>::cast(function_object);

210
  // The following conditions were lifted (in part) from the DCHECK inside
211
  // JSFunction::MarkForOptimization().
212 213

  if (!function->shared()->allows_lazy_compilation()) {
214
    return ReadOnlyRoots(isolate).undefined_value();
215
  }
216

217 218 219
  // If function isn't compiled, compile it now.
  if (!function->shared()->is_compiled() &&
      !Compiler::Compile(function, Compiler::CLEAR_EXCEPTION)) {
220
    return ReadOnlyRoots(isolate).undefined_value();
221 222
  }

223
  // If the function is already optimized, just return.
224
  if (function->IsOptimized() || function->shared()->HasAsmWasmData()) {
225
    return ReadOnlyRoots(isolate).undefined_value();
226
  }
227

228 229 230
  // If the function has optimized code, ensure that we check for it and return.
  if (function->HasOptimizedCode()) {
    DCHECK(function->ChecksOptimizationMarker());
231
    return ReadOnlyRoots(isolate).undefined_value();
232
  }
233

234
  ConcurrencyMode concurrency_mode = ConcurrencyMode::kNotConcurrent;
235
  if (args.length() == 2) {
236
    CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
237 238
    if (type->IsOneByteEqualTo(STATIC_CHAR_VECTOR("concurrent")) &&
        isolate->concurrent_recompilation_enabled()) {
239
      concurrency_mode = ConcurrencyMode::kConcurrent;
240 241
    }
  }
242 243 244 245 246 247 248 249
  if (FLAG_trace_opt) {
    PrintF("[manually marking ");
    function->ShortPrint();
    PrintF(" for %s optimization]\n",
           concurrency_mode == ConcurrencyMode::kConcurrent ? "concurrent"
                                                            : "non-concurrent");
  }

250 251 252 253
  // This function may not have been lazily compiled yet, even though its shared
  // function has.
  if (!function->is_compiled()) {
    DCHECK(function->shared()->IsInterpreted());
254
    function->set_code(*BUILTIN_CODE(isolate, InterpreterEntryTrampoline));
255
  }
256

257
  JSFunction::EnsureFeedbackVector(function);
258
  function->MarkForOptimization(concurrency_mode);
259

260
  return ReadOnlyRoots(isolate).undefined_value();
261 262
}

263 264
RUNTIME_FUNCTION(Runtime_OptimizeOsr) {
  HandleScope scope(isolate);
265
  DCHECK(args.length() == 0 || args.length() == 1);
266

267
  Handle<JSFunction> function;
268

269 270
  // The optional parameter determines the frame being targeted.
  int stack_depth = args.length() == 1 ? args.smi_at(0) : 0;
271

272 273 274
  // Find the JavaScript function on the top of the stack.
  JavaScriptFrameIterator it(isolate);
  while (!it.done() && stack_depth--) it.Advance();
275
  if (!it.done()) function = handle(it.frame()->function(), isolate);
276
  if (function.is_null()) return ReadOnlyRoots(isolate).undefined_value();
277

278
  // If the function is already optimized, just return.
279
  if (function->IsOptimized()) return ReadOnlyRoots(isolate).undefined_value();
280

281 282 283 284 285 286 287 288 289 290 291
  // Ensure that the function is marked for non-concurrent optimization, so that
  // subsequent runs don't also optimize.
  if (!function->HasOptimizedCode()) {
    if (FLAG_trace_osr) {
      PrintF("[OSR - OptimizeOsr marking ");
      function->ShortPrint();
      PrintF(" for non-concurrent optimization]\n");
    }
    function->MarkForOptimization(ConcurrencyMode::kNotConcurrent);
  }

292
  // Make the profiler arm all back edges in unoptimized code.
293
  if (it.frame()->type() == StackFrame::INTERPRETED) {
294
    isolate->runtime_profiler()->AttemptOnStackReplacement(
295
        it.frame(), AbstractCode::kMaxLoopNestingMarker);
296 297
  }

298
  return ReadOnlyRoots(isolate).undefined_value();
299 300 301
}


302 303
RUNTIME_FUNCTION(Runtime_NeverOptimizeFunction) {
  HandleScope scope(isolate);
304
  DCHECK_EQ(1, args.length());
305 306 307 308
  // This function is used by fuzzers to get coverage for optimizations
  // in compiler. Ignore calls on non-function objects to avoid runtime errors.
  CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0);
  if (!function_object->IsJSFunction()) {
309
    return ReadOnlyRoots(isolate).undefined_value();
310 311
  }
  Handle<JSFunction> function = Handle<JSFunction>::cast(function_object);
312 313
  function->shared()->DisableOptimization(
      BailoutReason::kOptimizationDisabledForTest);
314
  return ReadOnlyRoots(isolate).undefined_value();
315 316 317 318
}

RUNTIME_FUNCTION(Runtime_GetOptimizationStatus) {
  HandleScope scope(isolate);
319
  DCHECK(args.length() == 1 || args.length() == 2);
320
  int status = 0;
Mythri's avatar
Mythri committed
321
  if (!isolate->use_optimizer()) {
322 323 324 325 326 327 328
    status |= static_cast<int>(OptimizationStatus::kNeverOptimize);
  }
  if (FLAG_always_opt || FLAG_prepare_always_opt) {
    status |= static_cast<int>(OptimizationStatus::kAlwaysOptimize);
  }
  if (FLAG_deopt_every_n_times) {
    status |= static_cast<int>(OptimizationStatus::kMaybeDeopted);
329
  }
330 331 332 333 334

  // This function is used by fuzzers to get coverage for optimizations
  // in compiler. Ignore calls on non-function objects to avoid runtime errors.
  CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0);
  if (!function_object->IsJSFunction()) {
335
    return Smi::FromInt(status);
336 337
  }
  Handle<JSFunction> function = Handle<JSFunction>::cast(function_object);
338
  status |= static_cast<int>(OptimizationStatus::kIsFunction);
339

340 341
  bool sync_with_compiler_thread = true;
  if (args.length() == 2) {
342
    CONVERT_ARG_HANDLE_CHECKED(Object, sync_object, 1);
343 344
    if (!sync_object->IsString())
      return ReadOnlyRoots(isolate).undefined_value();
345
    Handle<String> sync = Handle<String>::cast(sync_object);
346 347 348 349
    if (sync->IsOneByteEqualTo(STATIC_CHAR_VECTOR("no sync"))) {
      sync_with_compiler_thread = false;
    }
  }
350

351 352 353
  if (isolate->concurrent_recompilation_enabled() &&
      sync_with_compiler_thread) {
    while (function->IsInOptimizationQueue()) {
354
      isolate->optimizing_compile_dispatcher()->InstallOptimizedFunctions();
355
      base::OS::Sleep(base::TimeDelta::FromMilliseconds(50));
356 357
    }
  }
358 359 360 361 362 363 364 365 366 367

  if (function->IsMarkedForOptimization()) {
    status |= static_cast<int>(OptimizationStatus::kMarkedForOptimization);
  } else if (function->IsInOptimizationQueue()) {
    status |=
        static_cast<int>(OptimizationStatus::kMarkedForConcurrentOptimization);
  } else if (function->IsInOptimizationQueue()) {
    status |= static_cast<int>(OptimizationStatus::kOptimizingConcurrently);
  }

368 369 370 371 372
  if (function->IsOptimized()) {
    status |= static_cast<int>(OptimizationStatus::kOptimized);
    if (function->code()->is_turbofanned()) {
      status |= static_cast<int>(OptimizationStatus::kTurboFanned);
    }
373
  }
374
  if (function->IsInterpreted()) {
375
    status |= static_cast<int>(OptimizationStatus::kInterpreted);
376
  }
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396

  // Additionally, detect activations of this frame on the stack, and report the
  // status of the topmost frame.
  JavaScriptFrame* frame = nullptr;
  JavaScriptFrameIterator it(isolate);
  while (!it.done()) {
    if (it.frame()->function() == *function) {
      frame = it.frame();
      break;
    }
    it.Advance();
  }
  if (frame != nullptr) {
    status |= static_cast<int>(OptimizationStatus::kIsExecuting);
    if (frame->is_optimized()) {
      status |=
          static_cast<int>(OptimizationStatus::kTopmostFrameIsTurboFanned);
    }
  }

397
  return Smi::FromInt(status);
398 399 400
}

RUNTIME_FUNCTION(Runtime_UnblockConcurrentRecompilation) {
401
  DCHECK_EQ(0, args.length());
402 403 404 405
  if (FLAG_block_concurrent_recompilation &&
      isolate->concurrent_recompilation_enabled()) {
    isolate->optimizing_compile_dispatcher()->Unblock();
  }
406
  return ReadOnlyRoots(isolate).undefined_value();
407 408
}

409 410 411 412
RUNTIME_FUNCTION(Runtime_GetDeoptCount) {
  HandleScope scope(isolate);
  DCHECK_EQ(1, args.length());
  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
413 414 415
  // Functions without a feedback vector have never deoptimized.
  if (!function->has_feedback_vector()) return Smi::kZero;
  return Smi::FromInt(function->feedback_vector()->deopt_count());
416 417
}

418 419 420
static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
  args.GetReturnValue().Set(args.This());
}
421

422 423
RUNTIME_FUNCTION(Runtime_GetUndetectable) {
  HandleScope scope(isolate);
424
  DCHECK_EQ(0, args.length());
425
  v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
426

427 428
  Local<v8::ObjectTemplate> desc = v8::ObjectTemplate::New(v8_isolate);
  desc->MarkAsUndetectable();
429
  desc->SetCallAsFunctionHandler(ReturnThis);
430 431 432 433
  Local<v8::Object> obj;
  if (!desc->NewInstance(v8_isolate->GetCurrentContext()).ToLocal(&obj)) {
    return nullptr;
  }
434 435 436
  return *Utils::OpenHandle(*obj);
}

437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
  double v1 = args[0]
                  ->NumberValue(v8::Isolate::GetCurrent()->GetCurrentContext())
                  .ToChecked();
  double v2 = args[1]
                  ->NumberValue(v8::Isolate::GetCurrent()->GetCurrentContext())
                  .ToChecked();
  args.GetReturnValue().Set(
      v8::Number::New(v8::Isolate::GetCurrent(), v1 - v2));
}

// Returns a callable object. The object returns the difference of its two
// parameters when it is called.
RUNTIME_FUNCTION(Runtime_GetCallable) {
  HandleScope scope(isolate);
452
  DCHECK_EQ(0, args.length());
453 454 455 456 457 458 459 460 461 462 463 464
  v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
  Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(v8_isolate);
  Local<ObjectTemplate> instance_template = t->InstanceTemplate();
  instance_template->SetCallAsFunctionHandler(call_as_function);
  v8_isolate->GetCurrentContext();
  Local<v8::Object> instance =
      t->GetFunction(v8_isolate->GetCurrentContext())
          .ToLocalChecked()
          ->NewInstance(v8_isolate->GetCurrentContext())
          .ToLocalChecked();
  return *Utils::OpenHandle(*instance);
}
465

466
RUNTIME_FUNCTION(Runtime_ClearFunctionFeedback) {
467
  HandleScope scope(isolate);
468
  DCHECK_EQ(1, args.length());
469
  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
470
  function->ClearTypeFeedbackInfo();
471
  return ReadOnlyRoots(isolate).undefined_value();
472 473
}

474 475 476
RUNTIME_FUNCTION(Runtime_SetWasmCompileControls) {
  HandleScope scope(isolate);
  v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
477
  CHECK_EQ(args.length(), 2);
478 479 480 481 482
  CONVERT_ARG_HANDLE_CHECKED(Smi, block_size, 0);
  CONVERT_BOOLEAN_ARG_CHECKED(allow_async, 1);
  WasmCompileControls& ctrl = (*g_PerIsolateWasmControls.Pointer())[v8_isolate];
  ctrl.AllowAnySizeForAsync = allow_async;
  ctrl.MaxWasmBufferSize = static_cast<uint32_t>(block_size->value());
483
  v8_isolate->SetWasmModuleCallback(WasmModuleOverride);
484
  return ReadOnlyRoots(isolate).undefined_value();
485 486 487 488
}

RUNTIME_FUNCTION(Runtime_SetWasmInstantiateControls) {
  HandleScope scope(isolate);
489
  v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
490
  CHECK_EQ(args.length(), 0);
491
  v8_isolate->SetWasmInstanceCallback(WasmInstanceOverride);
492
  return ReadOnlyRoots(isolate).undefined_value();
493 494
}

495 496
RUNTIME_FUNCTION(Runtime_NotifyContextDisposed) {
  HandleScope scope(isolate);
497
  DCHECK_EQ(0, args.length());
498
  isolate->heap()->NotifyContextDisposed(true);
499
  return ReadOnlyRoots(isolate).undefined_value();
500 501 502 503 504 505
}


RUNTIME_FUNCTION(Runtime_SetAllocationTimeout) {
  SealHandleScope shs(isolate);
  DCHECK(args.length() == 2 || args.length() == 3);
506
#ifdef V8_ENABLE_ALLOCATION_TIMEOUT
507
  CONVERT_INT32_ARG_CHECKED(timeout, 1);
508
  isolate->heap()->set_allocation_timeout(timeout);
509 510 511
#endif
#ifdef DEBUG
  CONVERT_INT32_ARG_CHECKED(interval, 0);
512 513 514 515 516 517 518 519 520 521 522
  FLAG_gc_interval = interval;
  if (args.length() == 3) {
    // Enable/disable inline allocation if requested.
    CONVERT_BOOLEAN_ARG_CHECKED(inline_allocation, 2);
    if (inline_allocation) {
      isolate->heap()->EnableInlineAllocation();
    } else {
      isolate->heap()->DisableInlineAllocation();
    }
  }
#endif
523
  return ReadOnlyRoots(isolate).undefined_value();
524 525 526 527 528
}


RUNTIME_FUNCTION(Runtime_DebugPrint) {
  SealHandleScope shs(isolate);
529
  DCHECK_EQ(1, args.length());
530

531 532 533 534
  // Hack: The argument is passed as Object* but here it's really a
  // MaybeObject*.
  MaybeObject* maybe_object = reinterpret_cast<MaybeObject*>(args[0]);

535
  StdoutStream os;
536 537
  if (maybe_object->IsClearedWeakHeapObject()) {
    os << "[weak cleared]";
538
  } else {
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
    Object* object;
    bool weak = false;
    if (maybe_object->IsWeakHeapObject()) {
      weak = true;
      object = maybe_object->ToWeakHeapObject();
    } else {
      // Strong reference or SMI.
      object = maybe_object->ToObject();
    }

#ifdef DEBUG
    if (object->IsString() && isolate->context() != nullptr) {
      DCHECK(!weak);
      // If we have a string, assume it's a code "marker"
      // and print some interesting cpu debugging info.
554
      object->Print(os);
555 556 557 558 559 560 561 562 563 564 565
      JavaScriptFrameIterator it(isolate);
      JavaScriptFrame* frame = it.frame();
      os << "fp = " << reinterpret_cast<void*>(frame->fp())
         << ", sp = " << reinterpret_cast<void*>(frame->sp())
         << ", caller_sp = " << reinterpret_cast<void*>(frame->caller_sp())
         << ": ";
    } else {
      os << "DebugPrint: ";
      if (weak) {
        os << "[weak] ";
      }
566
      object->Print(os);
567 568
    }
    if (object->IsHeapObject()) {
569
      HeapObject::cast(object)->map()->Print(os);
570
    }
571
#else
572 573 574 575 576
    if (weak) {
      os << "[weak] ";
    }
    // ShortPrint is available in release mode. Print is not.
    os << Brief(object);
577
#endif
578
  }
579
  os << std::endl;
580 581 582 583

  return args[0];  // return TOS
}

584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
RUNTIME_FUNCTION(Runtime_PrintWithNameForAssert) {
  SealHandleScope shs(isolate);
  DCHECK_EQ(2, args.length());

  CONVERT_ARG_CHECKED(String, name, 0);

  PrintF(" * ");
  StringCharacterStream stream(name);
  while (stream.HasMore()) {
    uint16_t character = stream.GetNext();
    PrintF("%c", character);
  }
  PrintF(": ");
  args[1]->ShortPrint();
  PrintF("\n");

600
  return ReadOnlyRoots(isolate).undefined_value();
601
}
602 603 604

RUNTIME_FUNCTION(Runtime_DebugTrace) {
  SealHandleScope shs(isolate);
605
  DCHECK_EQ(0, args.length());
606
  isolate->PrintStack(stdout);
607
  return ReadOnlyRoots(isolate).undefined_value();
608 609
}

610 611
RUNTIME_FUNCTION(Runtime_DebugTrackRetainingPath) {
  HandleScope scope(isolate);
612 613
  DCHECK_LE(1, args.length());
  DCHECK_GE(2, args.length());
614 615 616 617
  if (!FLAG_track_retaining_path) {
    PrintF("DebugTrackRetainingPath requires --track-retaining-path flag.\n");
  } else {
    CONVERT_ARG_HANDLE_CHECKED(HeapObject, object, 0);
618 619 620
    RetainingPathOption option = RetainingPathOption::kDefault;
    if (args.length() == 2) {
      CONVERT_ARG_HANDLE_CHECKED(String, str, 1);
621 622 623
      const char track_ephemeron_path[] = "track-ephemeron-path";
      if (str->IsOneByteEqualTo(STATIC_CHAR_VECTOR(track_ephemeron_path))) {
        option = RetainingPathOption::kTrackEphemeronPath;
624 625 626
      } else if (str->length() != 0) {
        PrintF("Unexpected second argument of DebugTrackRetainingPath.\n");
        PrintF("Expected an empty string or '%s', got '%s'.\n",
627
               track_ephemeron_path, str->ToCString().get());
628 629 630
      }
    }
    isolate->heap()->AddRetainingPathTarget(object, option);
631
  }
632
  return ReadOnlyRoots(isolate).undefined_value();
633
}
634 635 636 637 638

// This will not allocate (flatten the string), but it may run
// very slowly for very deeply nested ConsStrings.  For debugging use only.
RUNTIME_FUNCTION(Runtime_GlobalPrint) {
  SealHandleScope shs(isolate);
639
  DCHECK_EQ(1, args.length());
640 641

  CONVERT_ARG_CHECKED(String, string, 0);
642
  StringCharacterStream stream(string);
643 644 645 646 647 648 649 650 651
  while (stream.HasMore()) {
    uint16_t character = stream.GetNext();
    PrintF("%c", character);
  }
  return string;
}


RUNTIME_FUNCTION(Runtime_SystemBreak) {
652 653 654
  // The code below doesn't create handles, but when breaking here in GDB
  // having a handle scope might be useful.
  HandleScope scope(isolate);
655
  DCHECK_EQ(0, args.length());
656
  base::OS::DebugBreak();
657
  return ReadOnlyRoots(isolate).undefined_value();
658 659 660 661 662 663
}


// Sets a v8 flag.
RUNTIME_FUNCTION(Runtime_SetFlags) {
  SealHandleScope shs(isolate);
664
  DCHECK_EQ(1, args.length());
665
  CONVERT_ARG_CHECKED(String, arg, 0);
666
  std::unique_ptr<char[]> flags =
667 668
      arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
  FlagList::SetFlagsFromString(flags.get(), StrLength(flags.get()));
669
  return ReadOnlyRoots(isolate).undefined_value();
670 671
}

672 673 674 675 676 677 678 679 680 681
RUNTIME_FUNCTION(Runtime_SetForceSlowPath) {
  SealHandleScope shs(isolate);
  DCHECK_EQ(1, args.length());
  CONVERT_ARG_CHECKED(Object, arg, 0);
  if (arg->IsTrue(isolate)) {
    isolate->set_force_slow_path(true);
  } else {
    DCHECK(arg->IsFalse(isolate));
    isolate->set_force_slow_path(false);
  }
682
  return ReadOnlyRoots(isolate).undefined_value();
683
}
684 685 686

RUNTIME_FUNCTION(Runtime_Abort) {
  SealHandleScope shs(isolate);
687
  DCHECK_EQ(1, args.length());
688
  CONVERT_SMI_ARG_CHECKED(message_id, 0);
689
  const char* message = GetAbortReason(static_cast<AbortReason>(message_id));
690 691 692 693 694 695 696 697 698
  base::OS::PrintError("abort: %s\n", message);
  isolate->PrintStack(stderr);
  base::OS::Abort();
  UNREACHABLE();
}


RUNTIME_FUNCTION(Runtime_AbortJS) {
  HandleScope scope(isolate);
699
  DCHECK_EQ(1, args.length());
700
  CONVERT_ARG_HANDLE_CHECKED(String, message, 0);
701 702 703 704
  if (FLAG_disable_abortjs) {
    base::OS::PrintError("[disabled] abort: %s\n", message->ToCString().get());
    return nullptr;
  }
705 706 707 708 709 710 711
  base::OS::PrintError("abort: %s\n", message->ToCString().get());
  isolate->PrintStack(stderr);
  base::OS::Abort();
  UNREACHABLE();
}


712 713 714
RUNTIME_FUNCTION(Runtime_DisassembleFunction) {
  HandleScope scope(isolate);
#ifdef DEBUG
715
  DCHECK_EQ(1, args.length());
716 717
  // Get the function and make sure it is compiled.
  CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
718 719
  if (!func->is_compiled() &&
      !Compiler::Compile(func, Compiler::KEEP_EXCEPTION)) {
720
    return ReadOnlyRoots(isolate).exception();
721
  }
722
  StdoutStream os;
723
  func->code()->Print(os);
724 725
  os << std::endl;
#endif  // DEBUG
726
  return ReadOnlyRoots(isolate).undefined_value();
727 728
}

729
namespace {
730

731
int StackSize(Isolate* isolate) {
732 733 734 735 736
  int n = 0;
  for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++;
  return n;
}

737 738 739 740 741
void PrintIndentation(Isolate* isolate) {
  const int nmax = 80;
  int n = StackSize(isolate);
  if (n <= nmax) {
    PrintF("%4d:%*s", n, n, "");
742
  } else {
743
    PrintF("%4d:%*s", n, nmax, "...");
744 745 746
  }
}

747
}  // namespace
748 749 750

RUNTIME_FUNCTION(Runtime_TraceEnter) {
  SealHandleScope shs(isolate);
751 752 753 754
  DCHECK_EQ(0, args.length());
  PrintIndentation(isolate);
  JavaScriptFrame::PrintTop(isolate, stdout, true, false);
  PrintF(" {\n");
755
  return ReadOnlyRoots(isolate).undefined_value();
756 757 758 759 760
}


RUNTIME_FUNCTION(Runtime_TraceExit) {
  SealHandleScope shs(isolate);
761
  DCHECK_EQ(1, args.length());
762
  CONVERT_ARG_CHECKED(Object, obj, 0);
763 764 765 766
  PrintIndentation(isolate);
  PrintF("} -> ");
  obj->ShortPrint();
  PrintF("\n");
767 768 769
  return obj;  // return TOS
}

770 771
RUNTIME_FUNCTION(Runtime_HaveSameMap) {
  SealHandleScope shs(isolate);
772
  DCHECK_EQ(2, args.length());
773 774 775 776 777 778
  CONVERT_ARG_CHECKED(JSObject, obj1, 0);
  CONVERT_ARG_CHECKED(JSObject, obj2, 1);
  return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
}


ben's avatar
ben committed
779 780
RUNTIME_FUNCTION(Runtime_InNewSpace) {
  SealHandleScope shs(isolate);
781
  DCHECK_EQ(1, args.length());
ben's avatar
ben committed
782
  CONVERT_ARG_CHECKED(Object, obj, 0);
783
  return isolate->heap()->ToBoolean(Heap::InNewSpace(obj));
ben's avatar
ben committed
784 785
}

786 787 788
RUNTIME_FUNCTION(Runtime_IsAsmWasmCode) {
  SealHandleScope shs(isolate);
  DCHECK_EQ(1, args.length());
789
  CONVERT_ARG_CHECKED(JSFunction, function, 0);
790 791
  if (!function->shared()->HasAsmWasmData()) {
    // Doesn't have wasm data.
792
    return ReadOnlyRoots(isolate).false_value();
793
  }
794 795
  if (function->shared()->HasBuiltinId() &&
      function->shared()->builtin_id() == Builtins::kInstantiateAsmJs) {
796
    // Hasn't been compiled yet.
797
    return ReadOnlyRoots(isolate).false_value();
798
  }
799
  return ReadOnlyRoots(isolate).true_value();
800 801
}

802
namespace {
803 804
bool DisallowCodegenFromStringsCallback(v8::Local<v8::Context> context,
                                        v8::Local<v8::String> source) {
805 806 807 808 809 810
  return false;
}
}

RUNTIME_FUNCTION(Runtime_DisallowCodegenFromStrings) {
  SealHandleScope shs(isolate);
811 812
  DCHECK_EQ(1, args.length());
  CONVERT_BOOLEAN_ARG_CHECKED(flag, 0);
813
  v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
814 815
  v8_isolate->SetAllowCodeGenerationFromStringsCallback(
      flag ? DisallowCodegenFromStringsCallback : nullptr);
816
  return ReadOnlyRoots(isolate).undefined_value();
817 818 819 820 821 822 823 824 825
}

RUNTIME_FUNCTION(Runtime_DisallowWasmCodegen) {
  SealHandleScope shs(isolate);
  DCHECK_EQ(1, args.length());
  CONVERT_BOOLEAN_ARG_CHECKED(flag, 0);
  v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
  v8_isolate->SetAllowWasmCodeGenerationCallback(
      flag ? DisallowCodegenFromStringsCallback : nullptr);
826
  return ReadOnlyRoots(isolate).undefined_value();
827 828
}

829 830 831 832 833 834 835
RUNTIME_FUNCTION(Runtime_IsWasmCode) {
  SealHandleScope shs(isolate);
  DCHECK_EQ(1, args.length());
  CONVERT_ARG_CHECKED(JSFunction, function, 0);
  bool is_js_to_wasm = function->code()->kind() == Code::JS_TO_WASM_FUNCTION;
  return isolate->heap()->ToBoolean(is_js_to_wasm);
}
ben's avatar
ben committed
836

837 838 839
RUNTIME_FUNCTION(Runtime_IsWasmTrapHandlerEnabled) {
  DisallowHeapAllocation no_gc;
  DCHECK_EQ(0, args.length());
840
  return isolate->heap()->ToBoolean(trap_handler::IsTrapHandlerEnabled());
841 842 843 844 845 846 847 848 849
}

RUNTIME_FUNCTION(Runtime_GetWasmRecoveredTrapCount) {
  HandleScope shs(isolate);
  DCHECK_EQ(0, args.length());
  size_t trap_count = trap_handler::GetRecoveredTrapCount();
  return *isolate->factory()->NewNumberFromSize(trap_count);
}

850 851 852 853 854 855
#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name)       \
  RUNTIME_FUNCTION(Runtime_Has##Name) {                  \
    CONVERT_ARG_CHECKED(JSObject, obj, 0);               \
    return isolate->heap()->ToBoolean(obj->Has##Name()); \
  }

856
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
857 858 859 860 861
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SmiElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ObjectElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SmiOrObjectElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DoubleElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(HoleyElements)
862 863 864 865 866 867
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SloppyArgumentsElements)
// Properties test sitting with elements tests - not fooling anyone.
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties)

#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
868

869 870 871 872
#define FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype) \
  RUNTIME_FUNCTION(Runtime_HasFixed##Type##Elements) {                     \
    CONVERT_ARG_CHECKED(JSObject, obj, 0);                                 \
    return isolate->heap()->ToBoolean(obj->HasFixed##Type##Elements());    \
873 874 875 876 877
  }

TYPED_ARRAYS(FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION)

#undef FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
878

879 880 881 882 883
RUNTIME_FUNCTION(Runtime_ArraySpeciesProtector) {
  SealHandleScope shs(isolate);
  DCHECK_EQ(0, args.length());
  return isolate->heap()->ToBoolean(isolate->IsArraySpeciesLookupChainIntact());
}
884

885
RUNTIME_FUNCTION(Runtime_TypedArraySpeciesProtector) {
886 887
  SealHandleScope shs(isolate);
  DCHECK_EQ(0, args.length());
888 889 890 891 892 893 894 895 896
  return isolate->heap()->ToBoolean(
      isolate->IsTypedArraySpeciesLookupChainIntact());
}

RUNTIME_FUNCTION(Runtime_PromiseSpeciesProtector) {
  SealHandleScope shs(isolate);
  DCHECK_EQ(0, args.length());
  return isolate->heap()->ToBoolean(
      isolate->IsPromiseSpeciesLookupChainIntact());
897 898
}

899 900
// Take a compiled wasm module and serialize it into an array buffer, which is
// then returned.
901 902
RUNTIME_FUNCTION(Runtime_SerializeWasmModule) {
  HandleScope shs(isolate);
903
  DCHECK_EQ(1, args.length());
904
  CONVERT_ARG_HANDLE_CHECKED(WasmModuleObject, module_obj, 0);
905

906
  wasm::NativeModule* native_module = module_obj->native_module();
907 908
  wasm::WasmSerializer wasm_serializer(isolate, native_module);
  size_t compiled_size = wasm_serializer.GetSerializedNativeModuleSize();
909 910 911 912
  void* array_data = isolate->array_buffer_allocator()->Allocate(compiled_size);
  Handle<JSArrayBuffer> array_buffer = isolate->factory()->NewJSArrayBuffer();
  JSArrayBuffer::Setup(array_buffer, isolate, false, array_data, compiled_size);
  if (!array_data ||
913
      !wasm_serializer.SerializeNativeModule(
914
          {reinterpret_cast<uint8_t*>(array_data), compiled_size})) {
915
    return ReadOnlyRoots(isolate).undefined_value();
916 917
  }
  return *array_buffer;
918 919 920 921 922 923
}

// Take an array buffer and attempt to reconstruct a compiled wasm module.
// Return undefined if unsuccessful.
RUNTIME_FUNCTION(Runtime_DeserializeWasmModule) {
  HandleScope shs(isolate);
924
  DCHECK_EQ(2, args.length());
925
  CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 0);
926
  CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, wire_bytes, 1);
927

928
  uint8_t* mem_start = reinterpret_cast<uint8_t*>(buffer->backing_store());
929
  size_t mem_size = static_cast<size_t>(buffer->byte_length()->Number());
930

931 932
  // Note that {wasm::DeserializeNativeModule} will allocate. We assume the
  // JSArrayBuffer doesn't get relocated.
933 934 935 936 937
  bool already_external = wire_bytes->is_external();
  if (!already_external) {
    wire_bytes->set_is_external(true);
    isolate->heap()->UnregisterArrayBuffer(*wire_bytes);
  }
938
  MaybeHandle<WasmModuleObject> maybe_module_object =
939 940 941 942 943
      wasm::DeserializeNativeModule(
          isolate, {mem_start, mem_size},
          Vector<const uint8_t>(
              reinterpret_cast<uint8_t*>(wire_bytes->backing_store()),
              static_cast<int>(wire_bytes->byte_length()->Number())));
944 945 946 947
  if (!already_external) {
    wire_bytes->set_is_external(false);
    isolate->heap()->RegisterNewArrayBuffer(*wire_bytes);
  }
948 949
  Handle<WasmModuleObject> module_object;
  if (!maybe_module_object.ToHandle(&module_object)) {
950
    return ReadOnlyRoots(isolate).undefined_value();
951
  }
952
  return *module_object;
953
}
954

955
RUNTIME_FUNCTION(Runtime_HeapObjectVerify) {
956 957 958 959
  HandleScope shs(isolate);
  DCHECK_EQ(1, args.length());
  CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
#ifdef VERIFY_HEAP
960
  object->ObjectVerify(isolate);
961 962 963 964 965 966 967 968 969 970 971
#else
  CHECK(object->IsObject());
  if (object->IsHeapObject()) {
    CHECK(HeapObject::cast(*object)->map()->IsMap());
  } else {
    CHECK(object->IsSmi());
  }
#endif
  return isolate->heap()->ToBoolean(true);
}

972 973 974 975 976 977 978 979 980 981 982 983
RUNTIME_FUNCTION(Runtime_WasmGetNumberOfInstances) {
  SealHandleScope shs(isolate);
  DCHECK_EQ(1, args.length());
  CONVERT_ARG_HANDLE_CHECKED(WasmModuleObject, module_obj, 0);
  int instance_count = 0;
  WeakArrayList* weak_instance_list = module_obj->weak_instance_list();
  for (int i = 0; i < weak_instance_list->length(); ++i) {
    if (weak_instance_list->Get(i)->IsWeakHeapObject()) instance_count++;
  }
  return Smi::FromInt(instance_count);
}

984 985 986
RUNTIME_FUNCTION(Runtime_WasmNumInterpretedCalls) {
  DCHECK_EQ(1, args.length());
  HandleScope scope(isolate);
987
  CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
988 989 990 991 992
  if (!instance->has_debug_info()) return 0;
  uint64_t num = instance->debug_info()->NumInterpretedCalls();
  return *isolate->factory()->NewNumberFromSize(static_cast<size_t>(num));
}

993 994 995
RUNTIME_FUNCTION(Runtime_RedirectToWasmInterpreter) {
  DCHECK_EQ(2, args.length());
  HandleScope scope(isolate);
996
  CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
997 998 999 1000 1001
  CONVERT_SMI_ARG_CHECKED(function_index, 1);
  Handle<WasmDebugInfo> debug_info =
      WasmInstanceObject::GetOrCreateDebugInfo(instance);
  WasmDebugInfo::RedirectToInterpreter(debug_info,
                                       Vector<int>(&function_index, 1));
1002
  return ReadOnlyRoots(isolate).undefined_value();
1003 1004
}

1005 1006
RUNTIME_FUNCTION(Runtime_WasmTraceMemory) {
  HandleScope hs(isolate);
1007 1008 1009 1010 1011
  DCHECK_EQ(1, args.length());
  CONVERT_ARG_CHECKED(Smi, info_addr, 0);

  wasm::MemoryTracingInfo* info =
      reinterpret_cast<wasm::MemoryTracingInfo*>(info_addr);
1012 1013 1014 1015 1016 1017 1018

  // Find the caller wasm frame.
  StackTraceFrameIterator it(isolate);
  DCHECK(!it.done());
  DCHECK(it.is_wasm());
  WasmCompiledFrame* frame = WasmCompiledFrame::cast(it.frame());

1019 1020
  uint8_t* mem_start = reinterpret_cast<uint8_t*>(
      frame->wasm_instance()->memory_object()->array_buffer()->backing_store());
1021 1022
  int func_index = frame->function_index();
  int pos = frame->position();
1023
  // TODO(titzer): eliminate dependency on WasmModule definition here.
1024 1025
  int func_start =
      frame->wasm_instance()->module()->functions[func_index].code.offset();
1026
  wasm::ExecutionEngine eng = frame->wasm_code()->is_liftoff()
1027 1028 1029 1030
                                  ? wasm::ExecutionEngine::kLiftoff
                                  : wasm::ExecutionEngine::kTurbofan;
  wasm::TraceMemoryOperation(eng, info, func_index, pos - func_start,
                             mem_start);
1031
  return ReadOnlyRoots(isolate).undefined_value();
1032 1033
}

1034 1035 1036 1037 1038
RUNTIME_FUNCTION(Runtime_IsLiftoffFunction) {
  HandleScope shs(isolate);
  DCHECK_EQ(1, args.length());
  CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
  CHECK(WasmExportedFunction::IsWasmExportedFunction(*function));
1039 1040 1041
  Handle<WasmExportedFunction> exp_fun =
      Handle<WasmExportedFunction>::cast(function);
  wasm::NativeModule* native_module =
1042
      exp_fun->instance()->module_object()->native_module();
1043 1044 1045 1046
  uint32_t func_index = exp_fun->function_index();
  return isolate->heap()->ToBoolean(
      native_module->has_code(func_index) &&
      native_module->code(func_index)->is_liftoff());
1047 1048
}

1049 1050 1051 1052 1053
RUNTIME_FUNCTION(Runtime_CompleteInobjectSlackTracking) {
  HandleScope scope(isolate);
  DCHECK_EQ(1, args.length());

  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
1054
  object->map()->CompleteInobjectSlackTracking(isolate);
1055

1056
  return ReadOnlyRoots(isolate).undefined_value();
1057 1058
}

1059 1060 1061 1062 1063
RUNTIME_FUNCTION(Runtime_FreezeWasmLazyCompilation) {
  DCHECK_EQ(1, args.length());
  DisallowHeapAllocation no_gc;
  CONVERT_ARG_CHECKED(WasmInstanceObject, instance, 0);

1064
  instance->module_object()->native_module()->set_lazy_compile_frozen(true);
1065
  return ReadOnlyRoots(isolate).undefined_value();
1066 1067
}

1068 1069 1070 1071 1072 1073 1074 1075
RUNTIME_FUNCTION(Runtime_WasmMemoryHasFullGuardRegion) {
  DCHECK_EQ(1, args.length());
  DisallowHeapAllocation no_gc;
  CONVERT_ARG_CHECKED(WasmMemoryObject, memory, 0);

  return isolate->heap()->ToBoolean(memory->has_full_guard_region(isolate));
}

1076 1077
}  // namespace internal
}  // namespace v8