blob: 9ec29b9d4d365477eada258142a6d096bdae45b6 [file] [log] [blame]
// 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.
#include "src/runtime/runtime-utils.h"
#include "src/arguments.h"
#include "src/deoptimizer.h"
#include "src/frames-inl.h"
#include "src/full-codegen/full-codegen.h"
#include "src/isolate-inl.h"
#include "src/snapshot/natives.h"
namespace v8 {
namespace internal {
RUNTIME_FUNCTION(Runtime_ConstructDouble) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
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));
}
RUNTIME_FUNCTION(Runtime_DeoptimizeFunction) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
// 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 it is not a JSFunction, just return.
if (!function_object->IsJSFunction()) {
return isolate->heap()->undefined_value();
}
Handle<JSFunction> function = Handle<JSFunction>::cast(function_object);
if (!function->IsOptimized()) return isolate->heap()->undefined_value();
// TODO(turbofan): Deoptimization is not supported yet.
if (function->code()->is_turbofanned() &&
function->shared()->asm_function() && !FLAG_turbo_asm_deoptimization) {
return isolate->heap()->undefined_value();
}
Deoptimizer::DeoptimizeFunction(*function);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_DeoptimizeNow) {
HandleScope scope(isolate);
DCHECK(args.length() == 0);
Handle<JSFunction> function;
// If the argument is 'undefined', deoptimize the topmost
// function.
JavaScriptFrameIterator it(isolate);
while (!it.done()) {
if (it.frame()->is_java_script()) {
function = Handle<JSFunction>(it.frame()->function());
break;
}
}
if (function.is_null()) return isolate->heap()->undefined_value();
if (!function->IsOptimized()) return isolate->heap()->undefined_value();
// TODO(turbofan): Deoptimization is not supported yet.
if (function->code()->is_turbofanned() &&
function->shared()->asm_function() && !FLAG_turbo_asm_deoptimization) {
return isolate->heap()->undefined_value();
}
Deoptimizer::DeoptimizeFunction(*function);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_RunningInSimulator) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 0);
#if defined(USE_SIMULATOR)
return isolate->heap()->true_value();
#else
return isolate->heap()->false_value();
#endif
}
RUNTIME_FUNCTION(Runtime_IsConcurrentRecompilationSupported) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 0);
return isolate->heap()->ToBoolean(
isolate->concurrent_recompilation_enabled());
}
RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) {
HandleScope scope(isolate);
RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
// 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 it is not a JSFunction, just return.
if (!function_object->IsJSFunction()) {
return isolate->heap()->undefined_value();
}
Handle<JSFunction> function = Handle<JSFunction>::cast(function_object);
// The following assertion was lifted from the DCHECK inside
// JSFunction::MarkForOptimization().
RUNTIME_ASSERT(function->shared()->allows_lazy_compilation() ||
(function->code()->kind() == Code::FUNCTION &&
!function->shared()->optimization_disabled()));
// If the function is already optimized, just return.
if (function->IsOptimized()) return isolate->heap()->undefined_value();
function->MarkForOptimization();
Code* unoptimized = function->shared()->code();
if (args.length() == 2 && unoptimized->kind() == Code::FUNCTION) {
CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
if (type->IsOneByteEqualTo(STATIC_CHAR_VECTOR("concurrent")) &&
isolate->concurrent_recompilation_enabled()) {
function->AttemptConcurrentOptimization();
}
}
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_OptimizeOsr) {
HandleScope scope(isolate);
RUNTIME_ASSERT(args.length() == 0 || args.length() == 1);
Handle<JSFunction> function = Handle<JSFunction>::null();
if (args.length() == 0) {
// Find the JavaScript function on the top of the stack.
JavaScriptFrameIterator it(isolate);
while (!it.done()) {
if (it.frame()->is_java_script()) {
function = Handle<JSFunction>(it.frame()->function());
break;
}
}
if (function.is_null()) return isolate->heap()->undefined_value();
} else {
// Function was passed as an argument.
CONVERT_ARG_HANDLE_CHECKED(JSFunction, arg, 0);
function = arg;
}
// The following assertion was lifted from the DCHECK inside
// JSFunction::MarkForOptimization().
RUNTIME_ASSERT(function->shared()->allows_lazy_compilation() ||
!function->shared()->optimization_disabled());
// If function is interpreted, just return. OSR is not supported.
// TODO(4764): Remove this check when OSR is enabled in the interpreter.
if (function->shared()->HasBytecodeArray()) {
return isolate->heap()->undefined_value();
}
// If the function is already optimized, just return.
if (function->IsOptimized()) return isolate->heap()->undefined_value();
Code* unoptimized = function->shared()->code();
if (unoptimized->kind() == Code::FUNCTION) {
DCHECK(BackEdgeTable::Verify(isolate, unoptimized));
isolate->runtime_profiler()->AttemptOnStackReplacement(
*function, Code::kMaxLoopNestingMarker);
}
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_NeverOptimizeFunction) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_CHECKED(JSFunction, function, 0);
function->shared()->set_disable_optimization_reason(
kOptimizationDisabledForTest);
function->shared()->set_optimization_disabled(true);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_GetOptimizationStatus) {
HandleScope scope(isolate);
RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
if (!isolate->use_crankshaft()) {
return Smi::FromInt(4); // 4 == "never".
}
bool sync_with_compiler_thread = true;
if (args.length() == 2) {
CONVERT_ARG_HANDLE_CHECKED(String, sync, 1);
if (sync->IsOneByteEqualTo(STATIC_CHAR_VECTOR("no sync"))) {
sync_with_compiler_thread = false;
}
}
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
if (isolate->concurrent_recompilation_enabled() &&
sync_with_compiler_thread) {
while (function->IsInOptimizationQueue()) {
isolate->optimizing_compile_dispatcher()->InstallOptimizedFunctions();
base::OS::Sleep(base::TimeDelta::FromMilliseconds(50));
}
}
if (FLAG_always_opt || FLAG_prepare_always_opt) {
// With --always-opt, optimization status expectations might not
// match up, so just return a sentinel.
return Smi::FromInt(3); // 3 == "always".
}
if (FLAG_deopt_every_n_times) {
return Smi::FromInt(6); // 6 == "maybe deopted".
}
if (function->IsOptimized() && function->code()->is_turbofanned()) {
return Smi::FromInt(7); // 7 == "TurboFan compiler".
}
return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
: Smi::FromInt(2); // 2 == "no".
}
RUNTIME_FUNCTION(Runtime_UnblockConcurrentRecompilation) {
DCHECK(args.length() == 0);
RUNTIME_ASSERT(FLAG_block_concurrent_recompilation);
RUNTIME_ASSERT(isolate->concurrent_recompilation_enabled());
isolate->optimizing_compile_dispatcher()->Unblock();
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_GetOptimizationCount) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
return Smi::FromInt(function->shared()->opt_count());
}
RUNTIME_FUNCTION(Runtime_GetUndetectable) {
HandleScope scope(isolate);
DCHECK(args.length() == 0);
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
Local<v8::ObjectTemplate> desc = v8::ObjectTemplate::New(v8_isolate);
desc->MarkAsUndetectable();
Local<v8::Object> obj;
if (!desc->NewInstance(v8_isolate->GetCurrentContext()).ToLocal(&obj)) {
return nullptr;
}
return *Utils::OpenHandle(*obj);
}
RUNTIME_FUNCTION(Runtime_ClearFunctionTypeFeedback) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
function->ClearTypeFeedbackInfo();
Code* unoptimized = function->shared()->code();
if (unoptimized->kind() == Code::FUNCTION) {
unoptimized->ClearInlineCaches();
}
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_NotifyContextDisposed) {
HandleScope scope(isolate);
DCHECK(args.length() == 0);
isolate->heap()->NotifyContextDisposed(true);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_SetAllocationTimeout) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 2 || args.length() == 3);
#ifdef DEBUG
CONVERT_SMI_ARG_CHECKED(interval, 0);
CONVERT_SMI_ARG_CHECKED(timeout, 1);
isolate->heap()->set_allocation_timeout(timeout);
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
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_DebugPrint) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
OFStream os(stdout);
#ifdef DEBUG
if (args[0]->IsString()) {
// If we have a string, assume it's a code "marker"
// and print some interesting cpu debugging info.
JavaScriptFrameIterator it(isolate);
JavaScriptFrame* frame = it.frame();
os << "fp = " << static_cast<void*>(frame->fp())
<< ", sp = " << static_cast<void*>(frame->sp())
<< ", caller_sp = " << static_cast<void*>(frame->caller_sp()) << ": ";
} else {
os << "DebugPrint: ";
}
args[0]->Print(os);
if (args[0]->IsHeapObject()) {
os << "\n";
HeapObject::cast(args[0])->map()->Print(os);
}
#else
// ShortPrint is available in release mode. Print is not.
os << Brief(args[0]);
#endif
os << std::endl;
return args[0]; // return TOS
}
RUNTIME_FUNCTION(Runtime_DebugTrace) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 0);
isolate->PrintStack(stdout);
return isolate->heap()->undefined_value();
}
// 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);
DCHECK(args.length() == 1);
CONVERT_ARG_CHECKED(String, string, 0);
StringCharacterStream stream(string);
while (stream.HasMore()) {
uint16_t character = stream.GetNext();
PrintF("%c", character);
}
return string;
}
RUNTIME_FUNCTION(Runtime_SystemBreak) {
// The code below doesn't create handles, but when breaking here in GDB
// having a handle scope might be useful.
HandleScope scope(isolate);
DCHECK(args.length() == 0);
base::OS::DebugBreak();
return isolate->heap()->undefined_value();
}
// Sets a v8 flag.
RUNTIME_FUNCTION(Runtime_SetFlags) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_CHECKED(String, arg, 0);
base::SmartArrayPointer<char> flags =
arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
FlagList::SetFlagsFromString(flags.get(), StrLength(flags.get()));
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_Abort) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
CONVERT_SMI_ARG_CHECKED(message_id, 0);
const char* message =
GetBailoutReason(static_cast<BailoutReason>(message_id));
base::OS::PrintError("abort: %s\n", message);
isolate->PrintStack(stderr);
base::OS::Abort();
UNREACHABLE();
return NULL;
}
RUNTIME_FUNCTION(Runtime_AbortJS) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(String, message, 0);
base::OS::PrintError("abort: %s\n", message->ToCString().get());
isolate->PrintStack(stderr);
base::OS::Abort();
UNREACHABLE();
return NULL;
}
RUNTIME_FUNCTION(Runtime_NativeScriptsCount) {
DCHECK(args.length() == 0);
return Smi::FromInt(Natives::GetBuiltinsCount());
}
// Returns V8 version as a string.
RUNTIME_FUNCTION(Runtime_GetV8Version) {
HandleScope scope(isolate);
DCHECK(args.length() == 0);
const char* version_string = v8::V8::GetVersion();
return *isolate->factory()->NewStringFromAsciiChecked(version_string);
}
RUNTIME_FUNCTION(Runtime_DisassembleFunction) {
HandleScope scope(isolate);
#ifdef DEBUG
DCHECK(args.length() == 1);
// Get the function and make sure it is compiled.
CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
if (!Compiler::Compile(func, Compiler::KEEP_EXCEPTION)) {
return isolate->heap()->exception();
}
OFStream os(stdout);
func->code()->Print(os);
os << std::endl;
#endif // DEBUG
return isolate->heap()->undefined_value();
}
namespace {
int StackSize(Isolate* isolate) {
int n = 0;
for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++;
return n;
}
void PrintIndentation(Isolate* isolate) {
const int nmax = 80;
int n = StackSize(isolate);
if (n <= nmax) {
PrintF("%4d:%*s", n, n, "");
} else {
PrintF("%4d:%*s", n, nmax, "...");
}
}
} // namespace
RUNTIME_FUNCTION(Runtime_TraceEnter) {
SealHandleScope shs(isolate);
DCHECK_EQ(0, args.length());
PrintIndentation(isolate);
JavaScriptFrame::PrintTop(isolate, stdout, true, false);
PrintF(" {\n");
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_TraceExit) {
SealHandleScope shs(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_CHECKED(Object, obj, 0);
PrintIndentation(isolate);
PrintF("} -> ");
obj->ShortPrint();
PrintF("\n");
return obj; // return TOS
}
RUNTIME_FUNCTION(Runtime_TraceTailCall) {
SealHandleScope shs(isolate);
DCHECK_EQ(0, args.length());
PrintIndentation(isolate);
PrintF("} -> tail call ->\n");
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_GetExceptionDetails) {
HandleScope shs(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSObject, exception_obj, 0);
Factory* factory = isolate->factory();
Handle<JSMessageObject> message_obj =
isolate->CreateMessage(exception_obj, nullptr);
Handle<JSObject> message = factory->NewJSObject(isolate->object_function());
Handle<String> key;
Handle<Object> value;
key = factory->NewStringFromAsciiChecked("start_pos");
value = handle(Smi::FromInt(message_obj->start_position()), isolate);
JSObject::SetProperty(message, key, value, STRICT).Assert();
key = factory->NewStringFromAsciiChecked("end_pos");
value = handle(Smi::FromInt(message_obj->end_position()), isolate);
JSObject::SetProperty(message, key, value, STRICT).Assert();
return *message;
}
RUNTIME_FUNCTION(Runtime_HaveSameMap) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_CHECKED(JSObject, obj1, 0);
CONVERT_ARG_CHECKED(JSObject, obj2, 1);
return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
}
RUNTIME_FUNCTION(Runtime_InNewSpace) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_CHECKED(Object, obj, 0);
return isolate->heap()->ToBoolean(isolate->heap()->InNewSpace(obj));
}
#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()); \
}
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastObjectElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOrObjectElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SloppyArgumentsElements)
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FixedTypedArrayElements)
// Properties test sitting with elements tests - not fooling anyone.
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties)
#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
#define FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, s) \
RUNTIME_FUNCTION(Runtime_HasFixed##Type##Elements) { \
CONVERT_ARG_CHECKED(JSObject, obj, 0); \
return isolate->heap()->ToBoolean(obj->HasFixed##Type##Elements()); \
}
TYPED_ARRAYS(FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION)
#undef FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
RUNTIME_FUNCTION(Runtime_SpeciesProtector) {
SealHandleScope shs(isolate);
DCHECK_EQ(0, args.length());
return isolate->heap()->ToBoolean(isolate->IsArraySpeciesLookupChainIntact());
}
} // namespace internal
} // namespace v8