blob: bc743b6e70a8d2d8c051ac974e53ddc9fba12da3 [file] [log] [blame]
// Copyright 2017 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/api/api-inl.h"
#include "src/builtins/builtins-utils-inl.h"
#include "src/builtins/builtins.h"
#include "src/debug/interface-types.h"
#include "src/logging/counters.h"
#include "src/logging/log.h"
#include "src/objects/objects-inl.h"
namespace v8 {
namespace internal {
// -----------------------------------------------------------------------------
// Console
#define CONSOLE_METHOD_LIST(V) \
V(Debug, debug) \
V(Error, error) \
V(Info, info) \
V(Log, log) \
V(Warn, warn) \
V(Dir, dir) \
V(DirXml, dirXml) \
V(Table, table) \
V(Trace, trace) \
V(Group, group) \
V(GroupCollapsed, groupCollapsed) \
V(GroupEnd, groupEnd) \
V(Clear, clear) \
V(Count, count) \
V(CountReset, countReset) \
V(Assert, assert) \
V(Profile, profile) \
V(ProfileEnd, profileEnd) \
V(TimeLog, timeLog)
namespace {
void ConsoleCall(
Isolate* isolate, const internal::BuiltinArguments& args,
void (debug::ConsoleDelegate::*func)(const v8::debug::ConsoleCallArguments&,
const v8::debug::ConsoleContext&)) {
CHECK(!isolate->has_pending_exception());
CHECK(!isolate->has_scheduled_exception());
if (!isolate->console_delegate()) return;
HandleScope scope(isolate);
// Access check. The current context has to match the context of all
// arguments, otherwise the inspector might leak objects across contexts.
Handle<Context> context = handle(isolate->context(), isolate);
for (int i = 0; i < args.length(); ++i) {
Handle<Object> argument = args.at<Object>(i);
if (!argument->IsJSObject()) continue;
Handle<JSObject> argument_obj = Handle<JSObject>::cast(argument);
if (argument->IsAccessCheckNeeded(isolate) &&
!isolate->MayAccess(context, argument_obj)) {
isolate->ReportFailedAccessCheck(argument_obj);
return;
}
}
debug::ConsoleCallArguments wrapper(args);
Handle<Object> context_id_obj = JSObject::GetDataProperty(
args.target(), isolate->factory()->console_context_id_symbol());
int context_id =
context_id_obj->IsSmi() ? Handle<Smi>::cast(context_id_obj)->value() : 0;
Handle<Object> context_name_obj = JSObject::GetDataProperty(
args.target(), isolate->factory()->console_context_name_symbol());
Handle<String> context_name = context_name_obj->IsString()
? Handle<String>::cast(context_name_obj)
: isolate->factory()->anonymous_string();
(isolate->console_delegate()->*func)(
wrapper,
v8::debug::ConsoleContext(context_id, Utils::ToLocal(context_name)));
}
void LogTimerEvent(Isolate* isolate, BuiltinArguments args,
Logger::StartEnd se) {
if (!isolate->logger()->is_logging()) return;
HandleScope scope(isolate);
std::unique_ptr<char[]> name;
const char* raw_name = "default";
if (args.length() > 1 && args[1].IsString()) {
// Try converting the first argument to a string.
name = args.at<String>(1)->ToCString();
raw_name = name.get();
}
LOG(isolate, TimerEvent(se, raw_name));
}
} // namespace
#define CONSOLE_BUILTIN_IMPLEMENTATION(call, name) \
BUILTIN(Console##call) { \
ConsoleCall(isolate, args, &debug::ConsoleDelegate::call); \
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); \
return ReadOnlyRoots(isolate).undefined_value(); \
}
CONSOLE_METHOD_LIST(CONSOLE_BUILTIN_IMPLEMENTATION)
#undef CONSOLE_BUILTIN_IMPLEMENTATION
BUILTIN(ConsoleTime) {
LogTimerEvent(isolate, args, Logger::START);
ConsoleCall(isolate, args, &debug::ConsoleDelegate::Time);
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
return ReadOnlyRoots(isolate).undefined_value();
}
BUILTIN(ConsoleTimeEnd) {
LogTimerEvent(isolate, args, Logger::END);
ConsoleCall(isolate, args, &debug::ConsoleDelegate::TimeEnd);
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
return ReadOnlyRoots(isolate).undefined_value();
}
BUILTIN(ConsoleTimeStamp) {
LogTimerEvent(isolate, args, Logger::STAMP);
ConsoleCall(isolate, args, &debug::ConsoleDelegate::TimeStamp);
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
return ReadOnlyRoots(isolate).undefined_value();
}
namespace {
void InstallContextFunction(Isolate* isolate, Handle<JSObject> target,
const char* name, Builtins::Name builtin_id,
int context_id, Handle<Object> context_name) {
Factory* const factory = isolate->factory();
Handle<String> name_string =
Name::ToFunctionName(isolate, factory->InternalizeUtf8String(name))
.ToHandleChecked();
NewFunctionArgs args = NewFunctionArgs::ForBuiltinWithoutPrototype(
name_string, builtin_id, i::LanguageMode::kSloppy);
Handle<JSFunction> fun = factory->NewFunction(args);
fun->shared().set_native(true);
fun->shared().DontAdaptArguments();
fun->shared().set_length(1);
JSObject::AddProperty(isolate, fun, factory->console_context_id_symbol(),
handle(Smi::FromInt(context_id), isolate), NONE);
if (context_name->IsString()) {
JSObject::AddProperty(isolate, fun, factory->console_context_name_symbol(),
context_name, NONE);
}
JSObject::AddProperty(isolate, target, name_string, fun, NONE);
}
} // namespace
BUILTIN(ConsoleContext) {
HandleScope scope(isolate);
Factory* const factory = isolate->factory();
Handle<String> name = factory->InternalizeUtf8String("Context");
NewFunctionArgs arguments = NewFunctionArgs::ForFunctionWithoutCode(
name, isolate->sloppy_function_map(), LanguageMode::kSloppy);
Handle<JSFunction> cons = factory->NewFunction(arguments);
Handle<JSObject> prototype = factory->NewJSObject(isolate->object_function());
JSFunction::SetPrototype(cons, prototype);
Handle<JSObject> context = factory->NewJSObject(cons, AllocationType::kOld);
DCHECK(context->IsJSObject());
int id = isolate->last_console_context_id() + 1;
isolate->set_last_console_context_id(id);
#define CONSOLE_BUILTIN_SETUP(call, name) \
InstallContextFunction(isolate, context, #name, Builtins::kConsole##call, \
id, args.at(1));
CONSOLE_METHOD_LIST(CONSOLE_BUILTIN_SETUP)
#undef CONSOLE_BUILTIN_SETUP
InstallContextFunction(isolate, context, "time", Builtins::kConsoleTime, id,
args.at(1));
InstallContextFunction(isolate, context, "timeEnd", Builtins::kConsoleTimeEnd,
id, args.at(1));
InstallContextFunction(isolate, context, "timeStamp",
Builtins::kConsoleTimeStamp, id, args.at(1));
return *context;
}
#undef CONSOLE_METHOD_LIST
} // namespace internal
} // namespace v8