powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Константный экземпляр класса. Кто как делает?
25 сообщений из 94, страница 3 из 4
Константный экземпляр класса. Кто как делает?
    #39649882
Фотография NekZ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_devИли ты мне хочешь рассказать, как компилятор вставляет машинный код, оперирующий регистрами (R/E)SP и (R/E)BP? Не стОит!... Ровно тоже самое делает функция _malloca.


Расскажи-ка тогда, почему при /O2 кода больше с alloca?

Код здорового человека
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
struct MyClass{ int x; MyClass() { x = rand(); } int f() { return x; } };

int main()
{
    MyClass b;
    return b.f();
}



Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
EXTRN   rand:PROC
main    PROC                                            ; COMDAT
        jmp      rand
main    ENDP
MyClass::f, COMDAT PROC
        mov      eax, DWORD PTR [rcx]
        ret      0
MyClass::f ENDP
MyClass::MyClass, COMDAT PROC
        push     rbx
        sub      rsp, 32              ; 00000020H
        mov      rbx, rcx
        call     rand
        mov      DWORD PTR [rbx], eax
        mov      rax, rbx
        add      rsp, 32              ; 00000020H
        pop      rbx
        ret      0
MyClass::MyClass ENDP


Против
Код курильщика
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
struct MyClass{ int x; MyClass() { x = rand(); } int f() { return x; } };

int main()
{
    MyClass* p = (MyClass*)alloca(sizeof(MyClass));
    if (NULL != p) new(p) MyClass();
    return p->f();
}



Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
EXTRN   rand:PROC
EXTRN   __GSHandlerCheck:PROC
EXTRN   __security_check_cookie:PROC
__$ArrayPad$ = 0
main    PROC                                            ; COMDAT
        push     rbp
        sub      rsp, 48              ; 00000030H
        lea      rbp, QWORD PTR [rsp+32]
        mov      QWORD PTR [rbp+32], rbx
        mov      rax, QWORD PTR __security_cookie
        xor      rax, rbp
        mov      QWORD PTR __$ArrayPad$[rbp], rax
        mov      eax, DWORD PTR [rsp]
        sub      rsp, 16
        lea      rbx, QWORD PTR [rsp+32]
        mov      ecx, DWORD PTR [rbx]
        test     rbx, rbx
        je       SHORT $LN12@main
        call     rand
        mov      DWORD PTR [rbx], eax
$LN12@main:
        mov      eax, DWORD PTR [rbx]
        mov      rcx, QWORD PTR __$ArrayPad$[rbp]
        xor      rcx, rbp
        call     __security_check_cookie
        mov      rbx, QWORD PTR [rbp+32]
        lea      rsp, QWORD PTR [rbp+16]
        pop      rbp
        ret      0
main    ENDP
MyClass::f, COMDAT PROC
        mov      eax, DWORD PTR [rcx]
        ret      0
MyClass::f ENDP
MyClass::MyClass, COMDAT PROC
        push     rbx
        sub      rsp, 32              ; 00000020H
        mov      rbx, rcx
        call     rand
        mov      DWORD PTR [rbx], eax
        mov      rax, rbx
        add      rsp, 32              ; 00000020H
        pop      rbx
        ret      0
MyClass::MyClass ENDP
void * __ptr64 __cdecl operator new(unsigned __int64,void * __ptr64) PROC                       ; operator new, COMDAT
        mov      rax, rdx
        ret      0
void * __ptr64 __cdecl operator new(unsigned __int64,void * __ptr64) ENDP                       ; operator new
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39649914
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NekZ, какая, в данном случае разница, больше кода или меньше или откуда берётся код, выделяющий память на стеке - из библиотечной функции, встроенной функции или, собственно, вставляется компилятором? Речь идёт о ПРИНЦИПАХ размещения и инициализации экземпляра класса на стеке. Нафига тут твои детали, которые к этим принципам никакого прямого отношения не имеют?
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39649921
Фотография NekZ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_devNekZ, какая, в данном случае разница, больше кода или меньше или откуда берётся код, выделяющий память на стеке - из библиотечной функции, встроенной функции или, собственно, вставляется компилятором? Речь идёт о ПРИНЦИПАХ размещения и инициализации экземпляра класса на стеке. Нафига тут твои детали, которые к этим принципам никакого прямого отношения не имеют?
Точно того ты мог добиться безо всяких аллокаов
Код: plaintext
1.
2.
3.
    char buf[sizeof(MyClass)];
    MyClass* p = (MyClass*)buf;
    new(p) MyClass();


Сдаётся мне, ты просто хочешь поспорить.
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39649929
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NekZТочно того ты мог добиться безо всяких аллокаов
Код: plaintext
1.
2.
3.
    char buf[sizeof(MyClass)];
    MyClass* p = (MyClass*)buf;
    new(p) MyClass();


Сдаётся мне, ты просто хочешь поспорить.Мог! И что дальше? Речь не о способе выделения памяти.
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39650060
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
* Есть возможность "сказать" new const Type(), но нет возможности этот const хоть как-то "услышать" в реализации перегруженного оператора new, конструктора или деструктора класса;

Оператор NEW выделяет память под объект. Как думаешь, памяти всё равно, какой объект в ней лежит, изменяемый или нет?
Всё равно. Должен operator new зависеть от константности объекта, под который выделяется память ? Нет, не должен.

авторЗачем возможность писать const, если при создании экземпляра класса в куче этот const, ровным счётом, ни на что не влияет?


Ты сможешь этот объект привязать только к константной ссылке или константному указателю , и объект после создания не будет меняться.


* Есть возможность переопределить placement new, но компилятор не симулирует его вызов при определении экземпляра объекта на стеке, хотя, такое поведение было бы логичным;

placement new -- это способ вызвать конструтор и осуществить инициализацию нового объекта в данной памяти.
Создание объекта состоит из двух фаз:
выделяется память под объект каким-либо образом

в этой памяти инициализируется новый объект с помощью вызова конструктора.

На стеке (auto память) это происходит так:

выделяется память под объект путём резервирования места определённого объёма в стеке.

с помощью вызова конструктора там инициализируется объект.
placement new делает РОВНО второй пункт этого плана, т.е. при создании объекта на стеке именно как раз "эмулируется placement new", так что что тебе ещё надо от С++, не понятно.


* Можем специализировать шаблоны с дедукцией по параметрам конструктора, но не можем специализировать шаблоны с дедукцией по типу и квалификаторам объявления lvalue;

При создании объекта и удалении объекта объект должен быть изменён, в этом суть инициализации.
Объект сначала находится в неинициализированном состоянии, вызывается конструктор, и содержимое объекта меняется таким образом, что объект находится уже в инициализированном состоянии. Ключевое тут -- что меняется. ЭТо значит, что не смотря ни на какие квалификаторы, используемые при определении нового объекта, он ОБЯЗАН поменяться. Т.е. квалификаторы не должны и не могут работать в конструкторе. То же самое можно сказать и про разрушение объекта и деструктор.

Ну и на самом деле (если подумать) квалификаторами обладают не сами объекты, а ссылки на них (в любом виде).
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39650064
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NekZrdb_devПри размещении экземпляра класса на стеке компилятор сам выделяет память на стеке и инициализирует там экземпляр класса, что примерно равносильно :
Код: plaintext
1.
2.
MyClass* p = (MyClass*)alloca(sizeof(MyClass));
if (NULL != p) new(p) MyClass();



Спасибо, поржал

Не, ну он всё верно расписал, именно это и делается. Можно даже такое самому руками делать.
Если ты только не ржал над тем, что он не додумал, что это и есть эмуляция placement new, то ржал ты зря.
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39650073
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MasterZivНа стеке (auto память) это происходит так:
выделяется память под объект путём резервирования места определённого объёма в стеке.

с помощью вызова конструктора там инициализируется объект.
placement new делает РОВНО второй пункт этого плана, т.е. при создании объекта на стеке именно как раз "эмулируется placement new", так что что тебе ещё надо от С++, не понятно.
В моем понимании, "эмуляция placement new" это когда компилятор создает код вызова placement new независимо от того, создана ли реализация этого оператора компилятором по умолчанию (по моему, она до сих пор не создается по умолчанию и компилятор инициализирует экземпляр на стеке просто пиная конструктор) или же разработчик сделал эту реализацию самостоятельно.
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39650080
Фотография NekZ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MasterZivНе, ну он всё верно расписал, именно это и делается. Можно даже такое самому руками делать.
Если ты только не ржал над тем, что он не додумал, что это и есть эмуляция placement new, то ржал ты зря.
Ну как сказать. Я поржал над тем, что это данный товарищ посчитал создание объекта на стеке с прямым вызовом аллоки и placement new. С точки зрения результата выполнения кода, наверное, да, это равнозначно, но то, что происходит под капотом, совсем другое, что и было проиллюстрировано выше под спойлерами. Перед вызовом call передвигается sp на размер фрейма вниз, в то время как вызов аллоки двигает sp вниз уже внутри самой функции, т.е. после call и выполняет кучу ненужной работы, так как размер известен на этапе компиляции, поэтому столько кода и нагенерилось ненужного.
По той же логике можно точно так же сказать что удаление гланд через ж0пу и через рот -- вещи равнозначные.
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39650086
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NekZНу как сказать. Я поржал над тем, что это данный товарищ посчитал создание объекта на стеке с прямым вызовом аллоки и placement new. С точки зрения результата выполнения кода, наверное, да, это равнозначно, но то, что происходит под капотом, совсем другое, что и было проиллюстрировано выше под спойлерами.Я не хуже тебя знаю, что происходит под капотом. Ты тут не один "знаток" ассемблера и оптимизации машинного кода.
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39650100
Фотография NekZ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_devЯ не хуже тебя знаю, что происходит под капотом. Ты тут не один "знаток" ассемблера и оптимизации машинного кода.
Разве ты не понял в чём суть?
В этом.
rdb_devТак почему бы компилятору не создавать placement new по умолчанию, если он не переопределен и не симулировать его вызов? Получили бы более управляемое поведение.
Ещё раз смотрим в код здорового человека и не видим там operator new, в отличие от нижележащего. Компилятру не нужно это разбивать на отдельные фазы выдениеня памяти на стеке и вызова конструктора через placement new -- это лишние вызовы. Он делает как можно короче и так как он считает нужным.

P.S. Забавно, что clang с этим примером справляется лучше VS'а.
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39650495
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NekZКомпилятру не нужно это разбивать на отдельные фазы выдениеня памяти на стеке и вызова конструктора через placement new -- это лишние вызовы. Он делает как можно короче и так как он считает нужным.То есть компилятор не формирует код для расширения кадра стека при объявлении там экземпляра класса? Это делает конструктор объекта?
Фактически мы всё равно имеем "отдельные фазы" - отдельно расширение кадра стека и отдельно вызов конструктора, точно также, как отдельные фазы оператора new - отдельно выделение памяти из кучи и отдельно вызов конструктора.
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39650514
Фотография NekZ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_devТо есть компилятор не формирует код для расширения кадра стека при объявлении там экземпляра класса? Это делает конструктор объекта?

Формирует, так и есть.

rdb_devФактически мы всё равно имеем "отдельные фазы" - отдельно расширение кадра стека и отдельно вызов конструктора, точно также, как отдельные фазы оператора new - отдельно выделение памяти из кучи и отдельно вызов конструктора.
А вот здесь не факт, ведь если бы ты попробовал посмотреть что делают clang или gcc с тем же кодом:
Код: plaintext
1.
2.
main:
  jmp rand
Никаких вызовов оператора new. Вообще вызовов. Потому что будь оно так как ты хочешь, то мы бы лишились многих важных оптимизаций, приводящих именно к такому сгенеренному коду. И пример с MSVC компилятором это иллюстрирует наглядно.
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39650739
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NekZ, какая разница, как выглядит вызов, если точкой возврата всё равно будет адрес, запихнутый в стек крайним перед передачей управления на первую команду конструктора или чего-то там еще? Ты можешь вызвать привычно через call, запихать адрес возврата и пнуть через jmp, а можешь извратится, запихать в стек адрес, на который хочешь передать управление и сделать ret. В чем разница-то? Принципиально мы всё равно имеет два этапа - выделение памяти и вызов конструктора.
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39650790
Фотография NekZ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_dev,

Да, два этапа, только если компилятор считает, что не нужно делать никакого call'а, он не будет его делать
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
struct MyClass{ int x; MyClass() { x = rand(); } int f() { return x; } };

int main()
{
    MyClass b;
    return b.f();
}


clang и gcc сжали это в
Код: plaintext
1.
2.
main:
    jmp rand
Никакого call'а конструктора, никакого адреса возврата на стеке, просто тупой переход в ту функцию с тем же неизменным стеком.
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39650855
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NekZrdb_dev,

Да, два этапа, только если компилятор считает, что не нужно делать никакого call'а, он не будет его делать
[src c++]
struct MyClass{ int x; MyClass() { x = rand(); } int f() { return x; } };

int main()
{
MyClass b;
return b.f();
}

clang и gcc сжали это в
Код: plaintext
1.
2.
main:
    jmp rand
Никакого call'а конструктора, никакого адреса возврата на стеке, просто тупой переход в ту функцию с тем же неизменным стеком.С чего ты взял, что перед вызовом jmp на стеке нет адреса возврата из main, который позволяет, в данном случае, делать ret из метода MyClass::f() прямо в точку вызова main возвращая тот же int? Глянь-ка отладчиком!
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39650864
Фотография NekZ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_devС чего ты взял, что перед вызовом jmp на стеке нет адреса возврата из main, который позволяет, в данном случае, делать ret из метода MyClass::f() прямо в точку вызова main возвращая тот же int? Глянь-ка отладчиком!
С того, что я привык верить своим глазам. И та заглушка, которая была добавлена линковщиком (аля _start) в счёт не идёт, тупой редирект на другую функцию и больше ничего. Совсем ничего.
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39650893
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NekZrdb_devС чего ты взял, что перед вызовом jmp на стеке нет адреса возврата из main, который позволяет, в данном случае, делать ret из метода MyClass::f() прямо в точку вызова main возвращая тот же int? Глянь-ка отладчиком!
С того, что я привык верить своим глазам. И та заглушка, которая была добавлена линковщиком (аля _start) в счёт не идёт, тупой редирект на другую функцию и больше ничего. Совсем ничего.Конечно тупой редирект! Что же еще? Если функция возвращает тот же самый тип и является результатом main, то из main будет именно тупой "редирект" на MyClass::f(), так как адрес возврата из main уже на стеке, которым и воспользуется ret внутри f(), чтобы вернуть значение main в точку вызова. Это оптимизация данного конкретного случая.
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39650912
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NekZ, хотя, скорее всего, адрес в jmp указывает непосредственно на библиотечную функцию rand(), а не на MyClass::f(). Компилятор решил, что в данном случае ни экземпляр MyClass, ни его метод f() вообще не нужны.
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39650944
Фотография NekZ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_devКонечно тупой редирект! Что же еще? Если функция возвращает тот же самый тип и является результатом main, то из main будет именно тупой "редирект" на MyClass::f(), так как адрес возврата из main уже на стеке, которым и воспользуется ret внутри f(), чтобы вернуть значение main в точку вызова. Это оптимизация данного конкретного случая.
Да, пример чисто академический, и именно наличие вот таких вот случаев показывает, что именно компилятор сам решает что где и как рассматривать, на какие фазы разбивать такие-то операции с объектами, а в каких случаях можно всё заинлайнить, не добавляя лишний вызов, в каких случаях вообще всё выбросить как dead code и т.д. Такие решения принимаются в том числе ещё и на основе целевой архитектуры и многих других факторов.
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39650945
Фотография NekZ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_devNekZ, хотя, скорее всего, адрес в jmp указывает непосредственно на библиотечную функцию rand(), а не на MyClass::f(). Компилятор решил, что в данном случае ни экземпляр MyClass, ни его метод f() вообще не нужны.
Я до тебя это и пытаюсь донести.
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39651050
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rdb_devВ моем понимании, "эмуляция placement new" это когда компилятор создает код вызова placement new независимо от того, создана ли реализация этого оператора компилятором по умолчанию (по моему, она до сих пор не создается по умолчанию и компилятор инициализирует экземпляр на стеке просто пиная конструктор) или же разработчик сделал эту реализацию самостоятельно.

0) placement new не переопределяется.
1) код placement new -- это вызов констуктора с указанным placement-у указателем на память в виде this .
2) соответственно, код placement new всегда инлайнится. Это собственно один вызов функции.

Что тебе ещё надо эмулировать?
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39651052
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NekZMasterZivНе, ну он всё верно расписал, именно это и делается. Можно даже такое самому руками делать.
Если ты только не ржал над тем, что он не додумал, что это и есть эмуляция placement new, то ржал ты зря.
Ну как сказать. Я поржал над тем, что это данный товарищ посчитал создание объекта на стеке с прямым вызовом аллоки и placement new. С точки зрения результата выполнения кода, наверное, да, это равнозначно, но то, что происходит под капотом, совсем другое, что и было проиллюстрировано выше под спойлерами. Перед вызовом call передвигается sp на размер фрейма вниз, в то время как вызов аллоки двигает sp вниз уже внутри самой функции, т.е. после call и выполняет кучу ненужной работы, так как размер известен на этапе компиляции, поэтому столько кода и нагенерилось ненужного.
По той же логике можно точно так же сказать что удаление гланд через ж0пу и через рот -- вещи равнозначные.

Что то ты тут намутил. Он всё там вполне адекватно расписал и дал эквивалентный код.
Другое дело, что код этот нафиг не нужен, поскольку можно просто написать автоматическую переменную этого класса.
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39651053
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NekZrdb_devЯ не хуже тебя знаю, что происходит под капотом. Ты тут не один "знаток" ассемблера и оптимизации машинного кода.
Разве ты не понял в чём суть?
В этом.
rdb_devТак почему бы компилятору не создавать placement new по умолчанию, если он не переопределен и не симулировать его вызов? Получили бы более управляемое поведение.
Ещё раз смотрим в код здорового человека и не видим там operator new, в отличие от нижележащего. Компилятру не нужно это разбивать на отдельные фазы выдениеня памяти на стеке и вызова конструктора через placement new -- это лишние вызовы. Он делает как можно короче и так как он считает нужным.

P.S. Забавно, что clang с этим примером справляется лучше VS'а.

Ещё раз, ваш чисто теоретический спор лишён всякого смысла, поскольку все вызовы всего кода создания чего-то на стеке и потом вызова констуктора инлайнятся.
Абсолютно по барабану, как это всё происходит.
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39651071
Фотография NekZ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MasterZivЕщё раз, ваш чисто теоретический спор лишён всякого смысла, поскольку все вызовы всего кода создания чего-то на стеке и потом вызова констуктора инлайнятся.
Абсолютно по барабану, как это всё происходит.
Я об этом ниже написал, переходя от голой теории к конкретике.
...
Рейтинг: 0 / 0
Константный экземпляр класса. Кто как делает?
    #39651076
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NekZMasterZivЕщё раз, ваш чисто теоретический спор лишён всякого смысла, поскольку все вызовы всего кода создания чего-то на стеке и потом вызова констуктора инлайнятся.
Абсолютно по барабану, как это всё происходит.
Я об этом ниже написал, переходя от голой теории к конкретике.

Ну и?
Топик закрываю?
...
Рейтинг: 0 / 0
25 сообщений из 94, страница 3 из 4
Форумы / C++ [игнор отключен] [закрыт для гостей] / Константный экземпляр класса. Кто как делает?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]