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 debug::ConsoleCallArguments wrapper(args);
50 Handle<Object> context_id_obj = JSObject::GetDataProperty(
51 args.target(), isolate->factory()->console_context_id_symbol());
52 int context_id =
53 context_id_obj->IsSmi() ? Handle<Smi>::cast(context_id_obj)->value() : 0;
54 Handle<Object> context_name_obj = JSObject::GetDataProperty(
55 args.target(), isolate->factory()->console_context_name_symbol());
56 Handle<String> context_name = context_name_obj->IsString()
57 ? Handle<String>::cast(context_name_obj)
58 : isolate->factory()->anonymous_string();
59 (isolate->console_delegate()->*func)(
60 wrapper,
61 v8::debug::ConsoleContext(context_id, Utils::ToLocal(context_name)));
62 }
63
LogTimerEvent(Isolate * isolate,BuiltinArguments args,v8::LogEventStatus se)64 void LogTimerEvent(Isolate* isolate, BuiltinArguments args,
65 v8::LogEventStatus se) {
66 if (!isolate->logger()->is_logging()) return;
67 HandleScope scope(isolate);
68 std::unique_ptr<char[]> name;
69 const char* raw_name = "default";
70 if (args.length() > 1 && args[1].IsString()) {
71 // Try converting the first argument to a string.
72 name = args.at<String>(1)->ToCString();
73 raw_name = name.get();
74 }
75 LOG(isolate, TimerEvent(se, raw_name));
76 }
77 } // namespace
78
79 #define CONSOLE_BUILTIN_IMPLEMENTATION(call, name) \
80 BUILTIN(Console##call) { \
81 ConsoleCall(isolate, args, &debug::ConsoleDelegate::call); \
82 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); \
83 return ReadOnlyRoots(isolate).undefined_value(); \
84 }
85 CONSOLE_METHOD_LIST(CONSOLE_BUILTIN_IMPLEMENTATION)
86 #undef CONSOLE_BUILTIN_IMPLEMENTATION
87
BUILTIN(ConsoleTime)88 BUILTIN(ConsoleTime) {
89 LogTimerEvent(isolate, args, v8::LogEventStatus::kStart);
90 ConsoleCall(isolate, args, &debug::ConsoleDelegate::Time);
91 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
92 return ReadOnlyRoots(isolate).undefined_value();
93 }
94
BUILTIN(ConsoleTimeEnd)95 BUILTIN(ConsoleTimeEnd) {
96 LogTimerEvent(isolate, args, v8::LogEventStatus::kEnd);
97 ConsoleCall(isolate, args, &debug::ConsoleDelegate::TimeEnd);
98 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
99 return ReadOnlyRoots(isolate).undefined_value();
100 }
101
BUILTIN(ConsoleTimeStamp)102 BUILTIN(ConsoleTimeStamp) {
103 LogTimerEvent(isolate, args, v8::LogEventStatus::kStamp);
104 ConsoleCall(isolate, args, &debug::ConsoleDelegate::TimeStamp);
105 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
106 return ReadOnlyRoots(isolate).undefined_value();
107 }
108
109 namespace {
110
InstallContextFunction(Isolate * isolate,Handle<JSObject> target,const char * name,Builtin builtin,int context_id,Handle<Object> context_name)111 void InstallContextFunction(Isolate* isolate, Handle<JSObject> target,
112 const char* name, Builtin builtin, int context_id,
113 Handle<Object> context_name) {
114 Factory* const factory = isolate->factory();
115
116 Handle<NativeContext> context(isolate->native_context());
117 Handle<Map> map = isolate->sloppy_function_without_prototype_map();
118
119 Handle<String> name_string =
120 Name::ToFunctionName(isolate, factory->InternalizeUtf8String(name))
121 .ToHandleChecked();
122 Handle<SharedFunctionInfo> info =
123 factory->NewSharedFunctionInfoForBuiltin(name_string, builtin);
124 info->set_language_mode(LanguageMode::kSloppy);
125
126 Handle<JSFunction> fun =
127 Factory::JSFunctionBuilder{isolate, info, context}.set_map(map).Build();
128
129 fun->shared().set_native(true);
130 fun->shared().DontAdaptArguments();
131 fun->shared().set_length(1);
132
133 JSObject::AddProperty(isolate, fun, factory->console_context_id_symbol(),
134 handle(Smi::FromInt(context_id), isolate), NONE);
135 if (context_name->IsString()) {
136 JSObject::AddProperty(isolate, fun, factory->console_context_name_symbol(),
137 context_name, NONE);
138 }
139 JSObject::AddProperty(isolate, target, name_string, fun, NONE);
140 }
141
142 } // namespace
143
BUILTIN(ConsoleContext)144 BUILTIN(ConsoleContext) {
145 HandleScope scope(isolate);
146
147 Factory* const factory = isolate->factory();
148 Handle<String> name = factory->InternalizeUtf8String("Context");
149 Handle<SharedFunctionInfo> info =
150 factory->NewSharedFunctionInfoForBuiltin(name, Builtin::kIllegal);
151 info->set_language_mode(LanguageMode::kSloppy);
152
153 Handle<JSFunction> cons =
154 Factory::JSFunctionBuilder{isolate, info, isolate->native_context()}
155 .Build();
156
157 Handle<JSObject> prototype = factory->NewJSObject(isolate->object_function());
158 JSFunction::SetPrototype(cons, prototype);
159
160 Handle<JSObject> context = factory->NewJSObject(cons, AllocationType::kOld);
161 DCHECK(context->IsJSObject());
162 int id = isolate->last_console_context_id() + 1;
163 isolate->set_last_console_context_id(id);
164
165 #define CONSOLE_BUILTIN_SETUP(call, name) \
166 InstallContextFunction(isolate, context, #name, Builtin::kConsole##call, id, \
167 args.at(1));
168 CONSOLE_METHOD_LIST(CONSOLE_BUILTIN_SETUP)
169 #undef CONSOLE_BUILTIN_SETUP
170 InstallContextFunction(isolate, context, "time", Builtin::kConsoleTime, id,
171 args.at(1));
172 InstallContextFunction(isolate, context, "timeEnd", Builtin::kConsoleTimeEnd,
173 id, args.at(1));
174 InstallContextFunction(isolate, context, "timeStamp",
175 Builtin::kConsoleTimeStamp, id, args.at(1));
176
177 return *context;
178 }
179
180 #undef CONSOLE_METHOD_LIST
181
182 } // namespace internal
183 } // namespace v8
184