Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(477)

Side by Side Diff: third_party/WebKit/Source/platform/v8_inspector/V8DebuggerImpl.cpp

Issue 2087953004: Switch v8 inspector to stl collections (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Actually remove a value from the list Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2010-2011 Google Inc. All rights reserved. 2 * Copyright (c) 2010-2011 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
150 void V8DebuggerImpl::debuggerAgentDisabled() 150 void V8DebuggerImpl::debuggerAgentDisabled()
151 { 151 {
152 if (!--m_enabledAgentsCount) 152 if (!--m_enabledAgentsCount)
153 disable(); 153 disable();
154 } 154 }
155 155
156 V8DebuggerAgentImpl* V8DebuggerImpl::findEnabledDebuggerAgent(int contextGroupId ) 156 V8DebuggerAgentImpl* V8DebuggerImpl::findEnabledDebuggerAgent(int contextGroupId )
157 { 157 {
158 if (!contextGroupId) 158 if (!contextGroupId)
159 return nullptr; 159 return nullptr;
160 V8InspectorSessionImpl* session = m_sessions.get(contextGroupId); 160 SessionMap::iterator iter = m_sessions.find(contextGroupId);
161 if (session && session->debuggerAgent()->enabled()) 161 if (iter != m_sessions.end() && iter->second) {
dgozman 2016/06/24 17:01:13 Prefer early bail-out: if (iter == m_sessions.end(
dgozman 2016/06/24 17:01:13 iter->second is always non-null
eostroukhov-old 2016/06/24 22:24:25 Done.
eostroukhov-old 2016/06/24 22:24:25 Done.
162 return session->debuggerAgent(); 162 V8DebuggerAgentImpl* agent = iter->second->debuggerAgent();
163 if (agent->enabled()) {
dgozman 2016/06/24 17:01:13 style: extra {}
eostroukhov-old 2016/06/24 22:24:25 Done.
164 return agent;
165 }
166 }
163 return nullptr; 167 return nullptr;
164 } 168 }
165 169
166 V8DebuggerAgentImpl* V8DebuggerImpl::findEnabledDebuggerAgent(v8::Local<v8::Cont ext> context) 170 V8DebuggerAgentImpl* V8DebuggerImpl::findEnabledDebuggerAgent(v8::Local<v8::Cont ext> context)
167 { 171 {
168 return findEnabledDebuggerAgent(getGroupId(context)); 172 return findEnabledDebuggerAgent(getGroupId(context));
169 } 173 }
170 174
171 void V8DebuggerImpl::getCompiledScripts(int contextGroupId, protocol::Vector<V8D ebuggerParsedScript>& result) 175 void V8DebuggerImpl::getCompiledScripts(int contextGroupId, std::vector<V8Debugg erParsedScript>& result)
172 { 176 {
173 v8::HandleScope scope(m_isolate); 177 v8::HandleScope scope(m_isolate);
174 v8::MicrotasksScope microtasks(m_isolate, v8::MicrotasksScope::kDoNotRunMicr otasks); 178 v8::MicrotasksScope microtasks(m_isolate, v8::MicrotasksScope::kDoNotRunMicr otasks);
175 v8::Local<v8::Object> debuggerScript = m_debuggerScript.Get(m_isolate); 179 v8::Local<v8::Object> debuggerScript = m_debuggerScript.Get(m_isolate);
176 DCHECK(!debuggerScript->IsUndefined()); 180 DCHECK(!debuggerScript->IsUndefined());
177 v8::Local<v8::Function> getScriptsFunction = v8::Local<v8::Function>::Cast(d ebuggerScript->Get(v8InternalizedString("getScripts"))); 181 v8::Local<v8::Function> getScriptsFunction = v8::Local<v8::Function>::Cast(d ebuggerScript->Get(v8InternalizedString("getScripts")));
178 v8::Local<v8::Value> argv[] = { v8::Integer::New(m_isolate, contextGroupId) }; 182 v8::Local<v8::Value> argv[] = { v8::Integer::New(m_isolate, contextGroupId) };
179 v8::Local<v8::Value> value; 183 v8::Local<v8::Value> value;
180 if (!getScriptsFunction->Call(debuggerContext(), debuggerScript, PROTOCOL_AR RAY_LENGTH(argv), argv).ToLocal(&value)) 184 if (!getScriptsFunction->Call(debuggerContext(), debuggerScript, PROTOCOL_AR RAY_LENGTH(argv), argv).ToLocal(&value))
181 return; 185 return;
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
395 v8result = maybeResult.ToLocalChecked(); 399 v8result = maybeResult.ToLocalChecked();
396 } 400 }
397 DCHECK(!v8result.IsEmpty()); 401 DCHECK(!v8result.IsEmpty());
398 v8::Local<v8::Object> resultTuple = v8result->ToObject(m_isolate); 402 v8::Local<v8::Object> resultTuple = v8result->ToObject(m_isolate);
399 int code = static_cast<int>(resultTuple->Get(0)->ToInteger(m_isolate)->Value ()); 403 int code = static_cast<int>(resultTuple->Get(0)->ToInteger(m_isolate)->Value ());
400 switch (code) { 404 switch (code) {
401 case 0: 405 case 0:
402 { 406 {
403 *stackChanged = resultTuple->Get(1)->BooleanValue(); 407 *stackChanged = resultTuple->Get(1)->BooleanValue();
404 // Call stack may have changed after if the edited function was on t he stack. 408 // Call stack may have changed after if the edited function was on t he stack.
405 if (!preview && isPaused()) 409 if (!preview && isPaused()) {
406 newCallFrames->swap(currentCallFrames()); 410 JavaScriptCallFrames frames = currentCallFrames();
411 newCallFrames->swap(frames);
412 }
407 return true; 413 return true;
408 } 414 }
409 // Compile error. 415 // Compile error.
410 case 1: 416 case 1:
411 { 417 {
412 *errorData = protocol::Debugger::SetScriptSourceError::create() 418 *errorData = protocol::Debugger::SetScriptSourceError::create()
413 .setMessage(toProtocolStringWithTypeCheck(resultTuple->Get(2))) 419 .setMessage(toProtocolStringWithTypeCheck(resultTuple->Get(2)))
414 .setLineNumber(resultTuple->Get(3)->ToInteger(m_isolate)->Value( )) 420 .setLineNumber(resultTuple->Get(3)->ToInteger(m_isolate)->Value( ))
415 .setColumnNumber(resultTuple->Get(4)->ToInteger(m_isolate)->Valu e()).build(); 421 .setColumnNumber(resultTuple->Get(4)->ToInteger(m_isolate)->Valu e()).build();
416 return false; 422 return false;
(...skipping 20 matching lines...) Expand all
437 return JavaScriptCallFrames(); 443 return JavaScriptCallFrames();
438 v8::Local<v8::Array> callFramesArray = currentCallFramesV8.As<v8::Array>(); 444 v8::Local<v8::Array> callFramesArray = currentCallFramesV8.As<v8::Array>();
439 JavaScriptCallFrames callFrames; 445 JavaScriptCallFrames callFrames;
440 for (size_t i = 0; i < callFramesArray->Length(); ++i) { 446 for (size_t i = 0; i < callFramesArray->Length(); ++i) {
441 v8::Local<v8::Value> callFrameValue; 447 v8::Local<v8::Value> callFrameValue;
442 if (!callFramesArray->Get(debuggerContext(), i).ToLocal(&callFrameValue) ) 448 if (!callFramesArray->Get(debuggerContext(), i).ToLocal(&callFrameValue) )
443 return JavaScriptCallFrames(); 449 return JavaScriptCallFrames();
444 if (!callFrameValue->IsObject()) 450 if (!callFrameValue->IsObject())
445 return JavaScriptCallFrames(); 451 return JavaScriptCallFrames();
446 v8::Local<v8::Object> callFrameObject = callFrameValue.As<v8::Object>(); 452 v8::Local<v8::Object> callFrameObject = callFrameValue.As<v8::Object>();
447 callFrames.append(JavaScriptCallFrame::create(debuggerContext(), v8::Loc al<v8::Object>::Cast(callFrameObject))); 453 callFrames.push_back(JavaScriptCallFrame::create(debuggerContext(), v8:: Local<v8::Object>::Cast(callFrameObject)));
448 } 454 }
449 return callFrames; 455 return callFrames;
450 } 456 }
451 457
452 static V8DebuggerImpl* toV8DebuggerImpl(v8::Local<v8::Value> data) 458 static V8DebuggerImpl* toV8DebuggerImpl(v8::Local<v8::Value> data)
453 { 459 {
454 void* p = v8::Local<v8::External>::Cast(data)->Value(); 460 void* p = v8::Local<v8::External>::Cast(data)->Value();
455 return static_cast<V8DebuggerImpl*>(p); 461 return static_cast<V8DebuggerImpl*>(p);
456 } 462 }
457 463
(...skipping 10 matching lines...) Expand all
468 void V8DebuggerImpl::handleProgramBreak(v8::Local<v8::Context> pausedContext, v8 ::Local<v8::Object> executionState, v8::Local<v8::Value> exception, v8::Local<v8 ::Array> hitBreakpointNumbers, bool isPromiseRejection) 474 void V8DebuggerImpl::handleProgramBreak(v8::Local<v8::Context> pausedContext, v8 ::Local<v8::Object> executionState, v8::Local<v8::Value> exception, v8::Local<v8 ::Array> hitBreakpointNumbers, bool isPromiseRejection)
469 { 475 {
470 // Don't allow nested breaks. 476 // Don't allow nested breaks.
471 if (m_runningNestedMessageLoop) 477 if (m_runningNestedMessageLoop)
472 return; 478 return;
473 479
474 V8DebuggerAgentImpl* agent = findEnabledDebuggerAgent(pausedContext); 480 V8DebuggerAgentImpl* agent = findEnabledDebuggerAgent(pausedContext);
475 if (!agent) 481 if (!agent)
476 return; 482 return;
477 483
478 protocol::Vector<String16> breakpointIds; 484 std::vector<String16> breakpointIds;
479 if (!hitBreakpointNumbers.IsEmpty()) { 485 if (!hitBreakpointNumbers.IsEmpty()) {
480 breakpointIds.resize(hitBreakpointNumbers->Length()); 486 breakpointIds.reserve(hitBreakpointNumbers->Length());
481 for (size_t i = 0; i < hitBreakpointNumbers->Length(); i++) { 487 for (size_t i = 0; i < hitBreakpointNumbers->Length(); i++) {
482 v8::Local<v8::Value> hitBreakpointNumber = hitBreakpointNumbers->Get (i); 488 v8::Local<v8::Value> hitBreakpointNumber = hitBreakpointNumbers->Get (i);
483 DCHECK(!hitBreakpointNumber.IsEmpty() && hitBreakpointNumber->IsInt3 2()); 489 DCHECK(!hitBreakpointNumber.IsEmpty() && hitBreakpointNumber->IsInt3 2());
484 breakpointIds[i] = String16::number(hitBreakpointNumber->Int32Value( )); 490 breakpointIds.push_back(String16::number(hitBreakpointNumber->Int32V alue()));
485 } 491 }
486 } 492 }
487 493
488 m_pausedContext = pausedContext; 494 m_pausedContext = pausedContext;
489 m_executionState = executionState; 495 m_executionState = executionState;
490 V8DebuggerAgentImpl::SkipPauseRequest result = agent->didPause(pausedContext , exception, breakpointIds, isPromiseRejection); 496 V8DebuggerAgentImpl::SkipPauseRequest result = agent->didPause(pausedContext , exception, breakpointIds, isPromiseRejection);
491 if (result == V8DebuggerAgentImpl::RequestNoSkip) { 497 if (result == V8DebuggerAgentImpl::RequestNoSkip) {
492 m_runningNestedMessageLoop = true; 498 m_runningNestedMessageLoop = true;
493 int groupId = getGroupId(pausedContext); 499 int groupId = getGroupId(pausedContext);
494 DCHECK(groupId); 500 DCHECK(groupId);
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after
726 } 732 }
727 733
728 std::unique_ptr<V8StackTrace> V8DebuggerImpl::createStackTrace(v8::Local<v8::Sta ckTrace> stackTrace) 734 std::unique_ptr<V8StackTrace> V8DebuggerImpl::createStackTrace(v8::Local<v8::Sta ckTrace> stackTrace)
729 { 735 {
730 V8DebuggerAgentImpl* agent = findEnabledDebuggerAgent(m_isolate->GetCurrentC ontext()); 736 V8DebuggerAgentImpl* agent = findEnabledDebuggerAgent(m_isolate->GetCurrentC ontext());
731 return V8StackTraceImpl::create(agent, stackTrace, V8StackTrace::maxCallStac kSizeToCapture); 737 return V8StackTraceImpl::create(agent, stackTrace, V8StackTrace::maxCallStac kSizeToCapture);
732 } 738 }
733 739
734 std::unique_ptr<V8InspectorSession> V8DebuggerImpl::connect(int contextGroupId, protocol::FrontendChannel* channel, V8InspectorSessionClient* client, const Stri ng16* state) 740 std::unique_ptr<V8InspectorSession> V8DebuggerImpl::connect(int contextGroupId, protocol::FrontendChannel* channel, V8InspectorSessionClient* client, const Stri ng16* state)
735 { 741 {
736 DCHECK(!m_sessions.contains(contextGroupId)); 742 DCHECK(m_sessions.find(contextGroupId) == m_sessions.cend());
737 std::unique_ptr<V8InspectorSessionImpl> session = V8InspectorSessionImpl::cr eate(this, contextGroupId, channel, client, state); 743 std::unique_ptr<V8InspectorSessionImpl> session =
738 m_sessions.set(contextGroupId, session.get()); 744 V8InspectorSessionImpl::create(this, contextGroupId, channel, client, st ate);
745 m_sessions[contextGroupId] = session.get();
739 return std::move(session); 746 return std::move(session);
740 } 747 }
741 748
742 void V8DebuggerImpl::disconnect(V8InspectorSessionImpl* session) 749 void V8DebuggerImpl::disconnect(V8InspectorSessionImpl* session)
743 { 750 {
744 DCHECK(m_sessions.contains(session->contextGroupId())); 751 DCHECK(m_sessions.find(session->contextGroupId()) != m_sessions.end());
745 m_sessions.remove(session->contextGroupId()); 752 m_sessions.erase(session->contextGroupId());
746 } 753 }
747 754
748 void V8DebuggerImpl::contextCreated(const V8ContextInfo& info) 755 void V8DebuggerImpl::contextCreated(const V8ContextInfo& info)
749 { 756 {
750 DCHECK(info.context->GetIsolate() == m_isolate); 757 DCHECK(info.context->GetIsolate() == m_isolate);
751 // TODO(dgozman): make s_lastContextId non-static. 758 // TODO(dgozman): make s_lastContextId non-static.
752 int contextId = atomicIncrement(&s_lastContextId); 759 int contextId = atomicIncrement(&s_lastContextId);
753 String16 debugData = String16::number(info.contextGroupId) + "," + String16: :number(contextId) + "," + (info.isDefault ? "default" : "nondefault"); 760 String16 debugData = String16::number(info.contextGroupId) + "," + String16: :number(contextId) + "," + (info.isDefault ? "default" : "nondefault");
754 v8::HandleScope scope(m_isolate); 761 v8::HandleScope scope(m_isolate);
755 v8::Context::Scope contextScope(info.context); 762 v8::Context::Scope contextScope(info.context);
756 info.context->SetEmbedderData(static_cast<int>(v8::Context::kDebugIdIndex), toV8String(m_isolate, debugData)); 763 info.context->SetEmbedderData(static_cast<int>(v8::Context::kDebugIdIndex), toV8String(m_isolate, debugData));
757 764
758 if (!m_contexts.contains(info.contextGroupId)) 765 const auto& contextById =
759 m_contexts.set(info.contextGroupId, wrapUnique(new ContextByIdMap())); 766 m_contexts.insert(std::make_pair(info.contextGroupId, wrapUnique(new Con textByIdMap()))).first->second;
dgozman 2016/06/24 17:01:13 I think this creates an extra ContextByIdMap most
eostroukhov-old 2016/06/24 22:24:25 Done.
760 DCHECK(!m_contexts.get(info.contextGroupId)->contains(contextId));
761 767
762 std::unique_ptr<InspectedContext> contextOwner(new InspectedContext(this, in fo, contextId)); 768 DCHECK(contextById->find(contextId) == contextById->end());
dgozman 2016/06/24 17:01:13 cend?
eostroukhov-old 2016/06/24 22:24:25 Done.
763 InspectedContext* inspectedContext = contextOwner.get(); 769 InspectedContext* context = new InspectedContext(this, info, contextId);
764 m_contexts.get(info.contextGroupId)->set(contextId, std::move(contextOwner)) ; 770 bool inserted = contextById->insert(std::make_pair(contextId, wrapUnique(con text))).second;
dgozman 2016/06/24 17:01:13 Why not just contextById[contextId] = wrapUnique(c
eostroukhov-old 2016/06/24 22:24:25 Done.
765 771 DCHECK(inserted);
766 if (V8InspectorSessionImpl* session = m_sessions.get(info.contextGroupId)) 772 SessionMap::iterator session = m_sessions.find(info.contextGroupId);
dgozman 2016/06/24 17:01:13 nit: sessionIt
eostroukhov-old 2016/06/24 22:24:25 Done.
767 session->runtimeAgent()->reportExecutionContextCreated(inspectedContext) ; 773 if (session != m_sessions.end() && session->second) {
dgozman 2016/06/24 17:01:13 No need to check for session->second
dgozman 2016/06/24 17:01:13 style: extra {}
eostroukhov-old 2016/06/24 22:24:25 Done.
eostroukhov-old 2016/06/24 22:24:25 Done.
774 session->second->runtimeAgent()->reportExecutionContextCreated(context);
775 }
768 } 776 }
769 777
770 void V8DebuggerImpl::contextDestroyed(v8::Local<v8::Context> context) 778 void V8DebuggerImpl::contextDestroyed(v8::Local<v8::Context> context)
771 { 779 {
772 int contextId = V8Debugger::contextId(context); 780 int contextId = V8Debugger::contextId(context);
773 int contextGroupId = getGroupId(context); 781 int contextGroupId = getGroupId(context);
774 if (!m_contexts.contains(contextGroupId) || !m_contexts.get(contextGroupId)- >contains(contextId)) 782 if (!isContextInGroup(contextGroupId, contextId))
dgozman 2016/06/24 17:01:13 Let's make this method return InspectedContext* an
eostroukhov-old 2016/06/24 22:24:25 Done.
775 return; 783 return;
776 784
777 InspectedContext* inspectedContext = m_contexts.get(contextGroupId)->get(con textId); 785 SessionMap::iterator iter = m_sessions.find(contextGroupId);
778 if (V8InspectorSessionImpl* session = m_sessions.get(contextGroupId)) 786 if (iter != m_sessions.end()) {
779 session->runtimeAgent()->reportExecutionContextDestroyed(inspectedContex t); 787 const std::unique_ptr<InspectedContext>& inspectedContext =
780 788 (*m_contexts[contextGroupId])[contextId];
781 m_contexts.get(contextGroupId)->remove(contextId); 789 iter->second->runtimeAgent()
782 if (m_contexts.get(contextGroupId)->isEmpty()) 790 ->reportExecutionContextDestroyed(inspectedContext.get());
783 m_contexts.remove(contextGroupId); 791 }
792 discardInspectedContext(contextGroupId, contextId);
784 } 793 }
785 794
786 void V8DebuggerImpl::resetContextGroup(int contextGroupId) 795 void V8DebuggerImpl::resetContextGroup(int contextGroupId)
787 { 796 {
788 if (V8InspectorSessionImpl* session = m_sessions.get(contextGroupId)) 797 SessionMap::iterator session = m_sessions.find(contextGroupId);
789 session->reset(); 798 if (session != m_sessions.end() && session->second)
dgozman 2016/06/24 17:01:13 No need to check for session->second
eostroukhov-old 2016/06/24 22:24:25 Done.
790 m_contexts.remove(contextGroupId); 799 session->second->reset();
800 m_contexts.erase(contextGroupId);
791 } 801 }
792 802
793 void V8DebuggerImpl::willExecuteScript(v8::Local<v8::Context> context, int scrip tId) 803 void V8DebuggerImpl::willExecuteScript(v8::Local<v8::Context> context, int scrip tId)
794 { 804 {
795 if (V8DebuggerAgentImpl* agent = findEnabledDebuggerAgent(context)) 805 if (V8DebuggerAgentImpl* agent = findEnabledDebuggerAgent(context))
796 agent->willExecuteScript(scriptId); 806 agent->willExecuteScript(scriptId);
797 } 807 }
798 808
799 void V8DebuggerImpl::didExecuteScript(v8::Local<v8::Context> context) 809 void V8DebuggerImpl::didExecuteScript(v8::Local<v8::Context> context)
800 { 810 {
(...skipping 19 matching lines...) Expand all
820 830
821 v8::Local<v8::Context> V8DebuggerImpl::regexContext() 831 v8::Local<v8::Context> V8DebuggerImpl::regexContext()
822 { 832 {
823 if (m_regexContext.IsEmpty()) 833 if (m_regexContext.IsEmpty())
824 m_regexContext.Reset(m_isolate, v8::Context::New(m_isolate)); 834 m_regexContext.Reset(m_isolate, v8::Context::New(m_isolate));
825 return m_regexContext.Get(m_isolate); 835 return m_regexContext.Get(m_isolate);
826 } 836 }
827 837
828 void V8DebuggerImpl::discardInspectedContext(int contextGroupId, int contextId) 838 void V8DebuggerImpl::discardInspectedContext(int contextGroupId, int contextId)
829 { 839 {
830 if (!m_contexts.contains(contextGroupId) || !m_contexts.get(contextGroupId)- >contains(contextId)) 840 if (!isContextInGroup(contextGroupId, contextId))
831 return; 841 return;
832 m_contexts.get(contextGroupId)->remove(contextId); 842 m_contexts[contextGroupId]->erase(contextId);
833 if (m_contexts.get(contextGroupId)->isEmpty()) 843 if (m_contexts[contextGroupId]->empty())
834 m_contexts.remove(contextGroupId); 844 m_contexts.erase(contextGroupId);
835 } 845 }
836 846
837 const V8DebuggerImpl::ContextByIdMap* V8DebuggerImpl::contextGroup(int contextGr oupId) 847 const V8DebuggerImpl::ContextByIdMap* V8DebuggerImpl::contextGroup(int contextGr oupId)
838 { 848 {
839 if (!m_contexts.contains(contextGroupId)) 849 ContextsByGroupMap::iterator iter = m_contexts.find(contextGroupId);
840 return nullptr; 850 return iter == m_contexts.end() ? nullptr : iter->second.get();
841 return m_contexts.get(contextGroupId);
842 } 851 }
843 852
844 V8InspectorSessionImpl* V8DebuggerImpl::sessionForContextGroup(int contextGroupI d) 853 V8InspectorSessionImpl* V8DebuggerImpl::sessionForContextGroup(int contextGroupI d)
845 { 854 {
846 return contextGroupId ? m_sessions.get(contextGroupId) : nullptr; 855 if (contextGroupId) {
dgozman 2016/06/24 17:01:13 Prefer early return instead.
eostroukhov-old 2016/06/24 22:24:25 Done.
856 SessionMap::iterator iter = m_sessions.find(contextGroupId);
857 return iter == m_sessions.end() ? nullptr : iter->second;
858 }
859 return nullptr;
847 } 860 }
848 861
849 } // namespace blink 862 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698