1 // Copyright 2017 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 "src/api/api-inl.h"
6 #include "src/builtins/builtins-utils-inl.h"
7 #include "src/builtins/builtins.h"
8 #include "src/debug/interface-types.h"
9 #include "src/logging/counters.h"
10 #include "src/logging/log.h"
11 #include "src/objects/objects-inl.h"
12
13 namespace v8 {
14 namespace internal {
15
16 // -----------------------------------------------------------------------------
17 // Console
18
19 #define CONSOLE_METHOD_LIST(V) \
20 V(Debug, debug) \
21 V(Error, error) \
22 V(Info, info) \
23 V(Log, log) \
24 V(Warn, warn) \
25 V(Dir, dir) \
26 V(DirXml, dirXml) \
27 V(Table, table) \
28 V(Trace, trace) \
29 V(Group, group) \
30 V(GroupCollapsed, groupCollapsed) \
31 V(GroupEnd, groupEnd) \
32 V(Clear, clear) \
33 V(Count, count) \
34 V(CountReset, countReset) \
35 V(Assert, assert) \
36 V(Profile, profile) \
37 V(ProfileEnd, profileEnd) \
38 V(TimeLog, timeLog)
39
40 namespace {
ConsoleCall(Isolate * isolate,const internal::BuiltinArguments & args,void (debug::ConsoleDelegate::* func)(const v8::debug::ConsoleCallArguments &,const v8::debug::ConsoleContext &))41 void ConsoleCall(
42 Isolate* isolate, const internal::BuiltinArguments& args,
43 void (debug::ConsoleDelegate::*func)(const v8::debug::ConsoleCallArguments&,
44 const v8::debug::ConsoleContext&)) {
45 CHECK(!isolate->has_pending_exception());
46 CHECK(!isolate->has_scheduled_exception());
47 if (!isolate->console_delegate()) return;
48 HandleScope scope(isolate);
49
50 // Access check. The current context has to match the context of all
51 // arguments, otherwise the inspector might leak objects across contexts.
52 Handle<Context> context = handle(isolate->context(), isolate);
53 for (int i = 0; i < args.length(); ++i) {
54 Handle<Object> argument = args.at<Object>(i);
55 if (!argument->IsJSObject()) continue;
56
57 Handle<JSObject> argument_obj = Handle<JSObject>::cast(argument);
58 if (argument->IsAccessCheckNeeded(isolate) &&
59 !isolate->MayAccess(context, argument_obj)) {
60 isolate->ReportFailedAccessCheck(argument_obj);
61 return;
62 }
63 }
64
65 debug::ConsoleCallArguments wrapper(args);
66 Handle<Object> context_id_obj = JSObject::GetDataProperty(
67 args.target(), isolate->factory()->console_context_id_symbol());
68 int context_id =
69 context_id_obj->IsSmi() ? Handle<Smi>::cast(context_id_obj)->value() : 0;
70 Handle<Object> context_name_obj = JSObject::GetDataProperty(
71 args.target(), isolate->factory()->console_context_name_symbol());
72 Handle<String> context_name = context_name_obj->IsString()
73 ? Handle<String>::cast(context_name_obj)
74 : isolate->factory()->anonymous_string();
75 (isolate->console_delegate()->*func)(
76 wrapper,
77 v8::debug::ConsoleContext(context_id, Utils::ToLocal(context_name)));
78 }
79
LogTimerEvent(Isolate * isolate,BuiltinArguments args,Logger::StartEnd se)80 void LogTimerEvent(Isolate* isolate, BuiltinArguments args,
81 Logger::StartEnd se) {
82 if (!isolate->logger()->is_logging()) return;
83 HandleScope scope(isolate);
84 std::unique_ptr<char[]> name;
85 const char* raw_name = "default";
86 if (args.length() > 1 && args[1].IsString()) {
87 // Try converting the first argument to a string.
88 name = args.at<String>(1)->ToCString();
89 raw_name = name.get();
90 }
91 LOG(isolate, TimerEvent(se, raw_name));
92 }
93 } // namespace
94
95 #define CONSOLE_BUILTIN_IMPLEMENTATION(call, name) \
96 BUILTIN(Console##call) { \
97 ConsoleCall(isolate, args, &debug::ConsoleDelegate::call); \
98 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); \
99 return ReadOnlyRoots(isolate).undefined_value(); \
100 }
101 CONSOLE_METHOD_LIST(CONSOLE_BUILTIN_IMPLEMENTATION)
102 #undef CONSOLE_BUILTIN_IMPLEMENTATION
103
BUILTIN(ConsoleTime)104 BUILTIN(ConsoleTime) {
105 LogTimerEvent(isolate, args, Logger::START);
106 ConsoleCall(isolate, args, &debug::ConsoleDelegate::Time);
107 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
108 return ReadOnlyRoots(isolate).undefined_value();
109 }
110
BUILTIN(ConsoleTimeEnd)111 BUILTIN(ConsoleTimeEnd) {
112 LogTimerEvent(isolate, args, Logger::END);
113 ConsoleCall(isolate, args, &debug::ConsoleDelegate::TimeEnd);
114 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
115 return ReadOnlyRoots(isolate).undefined_value();
116 }
117
BUILTIN(ConsoleTimeStamp)118 BUILTIN(ConsoleTimeStamp) {
119 LogTimerEvent(isolate, args, Logger::STAMP);
120 ConsoleCall(isolate, args, &debug::ConsoleDelegate::TimeStamp);
121 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
122 return ReadOnlyRoots(isolate).undefined_value();
123 }
124
125 namespace {
InstallContextFunction(Isolate * isolate,Handle<JSObject> target,const char * name,Builtins::Name builtin_id,int context_id,Handle<Object> context_name)126 void InstallContextFunction(Isolate* isolate, Handle<JSObject> target,
127 const char* name, Builtins::Name builtin_id,
128 int context_id, Handle<Object> context_name) {
129 Factory* const factory = isolate->factory();
130
131 Handle<String> name_string =
132 Name::ToFunctionName(isolate, factory->InternalizeUtf8String(name))
133 .ToHandleChecked();
134 NewFunctionArgs args = NewFunctionArgs::ForBuiltinWithoutPrototype(
135 name_string, builtin_id, i::LanguageMode::kSloppy);
136 Handle<JSFunction> fun = factory->NewFunction(args);
137
138 fun->shared().set_native(true);
139 fun->shared().DontAdaptArguments();
140 fun->shared().set_length(1);
141
142 JSObject::AddProperty(isolate, fun, factory->console_context_id_symbol(),
143 handle(Smi::FromInt(context_id), isolate), NONE);
144 if (context_name->IsString()) {
145 JSObject::AddProperty(isolate, fun, factory->console_context_name_symbol(),
146 context_name, NONE);
147 }
148 JSObject::AddProperty(isolate, target, name_string, fun, NONE);
149 }
150 } // namespace
151
BUILTIN(ConsoleContext)152 BUILTIN(ConsoleContext) {
153 HandleScope scope(isolate);
154
155 Factory* const factory = isolate->factory();
156 Handle<String> name = factory->InternalizeUtf8String("Context");
157 NewFunctionArgs arguments = NewFunctionArgs::ForFunctionWithoutCode(
158 name, isolate->sloppy_function_map(), LanguageMode::kSloppy);
159 Handle<JSFunction> cons = factory->NewFunction(arguments);
160
161 Handle<JSObject> prototype = factory->NewJSObject(isolate->object_function());
162 JSFunction::SetPrototype(cons, prototype);
163
164 Handle<JSObject> context = factory->NewJSObject(cons, AllocationType::kOld);
165 DCHECK(context->IsJSObject());
166 int id = isolate->last_console_context_id() + 1;
167 isolate->set_last_console_context_id(id);
168
169 #define CONSOLE_BUILTIN_SETUP(call, name) \
170 InstallContextFunction(isolate, context, #name, Builtins::kConsole##call, \
171 id, args.at(1));
172 CONSOLE_METHOD_LIST(CONSOLE_BUILTIN_SETUP)
173 #undef CONSOLE_BUILTIN_SETUP
174 InstallContextFunction(isolate, context, "time", Builtins::kConsoleTime, id,
175 args.at(1));
176 InstallContextFunction(isolate, context, "timeEnd", Builtins::kConsoleTimeEnd,
177 id, args.at(1));
178 InstallContextFunction(isolate, context, "timeStamp",
179 Builtins::kConsoleTimeStamp, id, args.at(1));
180
181 return *context;
182 }
183
184 #undef CONSOLE_METHOD_LIST
185
186 } // namespace internal
187 } // namespace v8
188