Chromium Code Reviews| Index: third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp |
| diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp |
| index ceb485bdbf6c7e4ddd84cb242e0e556ae3c88ebf..1d461a758b4e6f576b403bd4122f15fc04ba1828 100644 |
| --- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp |
| +++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp |
| @@ -27,6 +27,7 @@ |
| #include "bindings/core/v8/ExceptionMessages.h" |
| #include "bindings/core/v8/ExceptionState.h" |
| +#include "bindings/core/v8/V8BindingMacros.h" |
| #include "bindings/modules/v8/WebGLAny.h" |
| #include "core/dom/DOMArrayBuffer.h" |
| #include "core/dom/DOMTypedArray.h" |
| @@ -1402,7 +1403,7 @@ void WebGLRenderingContextBase::attachShader(ScriptState* scriptState, WebGLProg |
| } |
| contextGL()->AttachShader(objectOrZero(program), objectOrZero(shader)); |
| shader->onAttached(); |
| - preserveObjectWrapper(scriptState, program, "shader", shader->type(), shader); |
| + preserveObjectWrapper(scriptState, program, V8HiddenValue::webglShaders(scriptState->isolate()), program->getPersistentCache(), static_cast<uint32_t>(shader->type()), shader); |
| } |
| void WebGLRenderingContextBase::bindAttribLocation(WebGLProgram* program, GLuint index, const String& name) |
| @@ -1471,7 +1472,17 @@ void WebGLRenderingContextBase::bindBuffer(ScriptState* scriptState, GLenum targ |
| return; |
| contextGL()->BindBuffer(target, objectOrZero(buffer)); |
| - preserveObjectWrapper(scriptState, this, "buffer", target, buffer); |
| + PreservedWrapperIndex idx; |
| + switch (target) { |
| + case GL_ARRAY_BUFFER: |
| + idx = PreservedArrayBuffer; |
| + break; |
| + case GL_ELEMENT_ARRAY_BUFFER: |
| + idx = PreservedElementArrayBuffer; |
| + break; |
| + } |
| + |
| + preserveObjectWrapper(scriptState, this, V8HiddenValue::webglMisc(scriptState->isolate()), &m_miscWrappers, static_cast<uint32_t>(idx), buffer); |
| maybePreserveDefaultVAOObjectWrapper(scriptState); |
| } |
| @@ -1492,8 +1503,9 @@ void WebGLRenderingContextBase::bindFramebuffer(ScriptState* scriptState, GLenum |
| setFramebuffer(target, buffer); |
| // This is called both internally and externally (from JavaScript). We only update which wrapper |
| // is preserved when it's called from JavaScript. |
| - if (scriptState) |
| - preserveObjectWrapper(scriptState, this, "framebuffer", 0, buffer); |
| + if (scriptState) { |
| + preserveObjectWrapper(scriptState, this, V8HiddenValue::webglMisc(scriptState->isolate()), &m_miscWrappers, static_cast<uint32_t>(PreservedFramebuffer), buffer); |
| + } |
| } |
| void WebGLRenderingContextBase::bindRenderbuffer(ScriptState* scriptState, GLenum target, WebGLRenderbuffer* renderBuffer) |
| @@ -1509,7 +1521,7 @@ void WebGLRenderingContextBase::bindRenderbuffer(ScriptState* scriptState, GLenu |
| } |
| m_renderbufferBinding = renderBuffer; |
| contextGL()->BindRenderbuffer(target, objectOrZero(renderBuffer)); |
| - preserveObjectWrapper(scriptState, this, "renderbuffer", 0, renderBuffer); |
| + preserveObjectWrapper(scriptState, this, V8HiddenValue::webglMisc(scriptState->isolate()), &m_miscWrappers, PreservedRenderbuffer, renderBuffer); |
| drawingBuffer()->setRenderbufferBinding(objectOrZero(renderBuffer)); |
| @@ -1529,22 +1541,38 @@ void WebGLRenderingContextBase::bindTexture(ScriptState* scriptState, GLenum tar |
| return; |
| } |
| - const char* bindingPointName = nullptr; |
| + // ScriptState may be null if this method is called internally |
| + // during restoration of texture unit bindings. Skip the |
| + // preserveObjectWrapper work in this case. |
| + v8::Local<v8::String> hiddenValueName; |
| + v8::Persistent<v8::Array>* persistentCache; |
| if (target == GL_TEXTURE_2D) { |
| m_textureUnits[m_activeTextureUnit].m_texture2DBinding = texture; |
| if (!m_activeTextureUnit) |
| drawingBuffer()->setTexture2DBinding(objectOrZero(texture)); |
| - bindingPointName = "texture_2d"; |
| + if (scriptState) { |
| + hiddenValueName = V8HiddenValue::webgl2DTextures(scriptState->isolate()); |
| + persistentCache = &m_2DTextureWrappers; |
| + } |
| } else if (target == GL_TEXTURE_CUBE_MAP) { |
| m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding = texture; |
| - bindingPointName = "texture_cube_map"; |
| + if (scriptState) { |
| + hiddenValueName = V8HiddenValue::webglCubeMapTextures(scriptState->isolate()); |
| + persistentCache = &m_cubeMapTextureWrappers; |
| + } |
| } else if (isWebGL2OrHigher() && target == GL_TEXTURE_2D_ARRAY) { |
| m_textureUnits[m_activeTextureUnit].m_texture2DArrayBinding = texture; |
| - bindingPointName = "texture_2d_array"; |
| + if (scriptState) { |
| + hiddenValueName = V8HiddenValue::webgl2DArrayTextures(scriptState->isolate()); |
| + persistentCache = &m_2DArrayTextureWrappers; |
| + } |
| } else if (isWebGL2OrHigher() && target == GL_TEXTURE_3D) { |
| m_textureUnits[m_activeTextureUnit].m_texture3DBinding = texture; |
| - bindingPointName = "texture_3d"; |
| + if (scriptState) { |
| + hiddenValueName = V8HiddenValue::webgl3DTextures(scriptState->isolate()); |
| + persistentCache = &m_3DTextureWrappers; |
| + } |
| } else { |
| synthesizeGLError(GL_INVALID_ENUM, "bindTexture", "invalid target"); |
| return; |
| @@ -1554,7 +1582,7 @@ void WebGLRenderingContextBase::bindTexture(ScriptState* scriptState, GLenum tar |
| // This is called both internally and externally (from JavaScript). We only update which wrapper |
| // is preserved when it's called from JavaScript. |
| if (scriptState) { |
| - preserveObjectWrapper(scriptState, this, bindingPointName, m_activeTextureUnit, texture); |
| + preserveObjectWrapper(scriptState, this, hiddenValueName, persistentCache, m_activeTextureUnit, texture); |
| } |
| if (texture) { |
| texture->setTarget(target); |
| @@ -1957,7 +1985,7 @@ void WebGLRenderingContextBase::setBoundVertexArrayObject(ScriptState* scriptSta |
| else |
| m_boundVertexArrayObject = m_defaultVertexArrayObject; |
| - preserveObjectWrapper(scriptState, this, "boundvao", 0, arrayObject); |
| + preserveObjectWrapper(scriptState, this, V8HiddenValue::webglMisc(scriptState->isolate()), &m_miscWrappers, static_cast<uint32_t>(PreservedVAO), arrayObject); |
| } |
| WebGLShader* WebGLRenderingContextBase::createShader(GLenum type) |
| @@ -2118,7 +2146,7 @@ void WebGLRenderingContextBase::detachShader(ScriptState* scriptState, WebGLProg |
| } |
| contextGL()->DetachShader(objectOrZero(program), objectOrZero(shader)); |
| shader->onDetached(contextGL()); |
| - preserveObjectWrapper(scriptState, program, "shader", shader->type(), nullptr); |
| + preserveObjectWrapper(scriptState, program, V8HiddenValue::webglShaders(scriptState->isolate()), program->getPersistentCache(), static_cast<uint32_t>(shader->type()), nullptr); |
| } |
| void WebGLRenderingContextBase::disable(GLenum cap) |
| @@ -2292,12 +2320,12 @@ void WebGLRenderingContextBase::framebufferRenderbuffer(ScriptState* scriptState |
| contextGL()->FramebufferRenderbuffer(target, GL_STENCIL_ATTACHMENT, renderbuffertarget, bufferObject); |
| framebufferBinding->setAttachmentForBoundFramebuffer(target, GL_DEPTH_ATTACHMENT, buffer); |
| framebufferBinding->setAttachmentForBoundFramebuffer(target, GL_STENCIL_ATTACHMENT, buffer); |
| - preserveObjectWrapper(scriptState, framebufferBinding, "attachment", GL_DEPTH_ATTACHMENT, buffer); |
| - preserveObjectWrapper(scriptState, framebufferBinding, "attachment", GL_STENCIL_ATTACHMENT, buffer); |
| + preserveObjectWrapper(scriptState, framebufferBinding, V8HiddenValue::webglAttachments(scriptState->isolate()), framebufferBinding->getPersistentCache(), GL_DEPTH_ATTACHMENT, buffer); |
| + preserveObjectWrapper(scriptState, framebufferBinding, V8HiddenValue::webglAttachments(scriptState->isolate()), framebufferBinding->getPersistentCache(), GL_STENCIL_ATTACHMENT, buffer); |
| } else { |
| contextGL()->FramebufferRenderbuffer(target, attachment, renderbuffertarget, bufferObject); |
| framebufferBinding->setAttachmentForBoundFramebuffer(target, attachment, buffer); |
| - preserveObjectWrapper(scriptState, framebufferBinding, "attachment", attachment, buffer); |
| + preserveObjectWrapper(scriptState, framebufferBinding, V8HiddenValue::webglAttachments(scriptState->isolate()), framebufferBinding->getPersistentCache(), attachment, buffer); |
| } |
| applyStencilTest(); |
| } |
| @@ -2326,12 +2354,12 @@ void WebGLRenderingContextBase::framebufferTexture2D(ScriptState* scriptState, G |
| contextGL()->FramebufferTexture2D(target, GL_STENCIL_ATTACHMENT, textarget, textureObject, level); |
| framebufferBinding->setAttachmentForBoundFramebuffer(target, GL_DEPTH_ATTACHMENT, textarget, texture, level, 0); |
| framebufferBinding->setAttachmentForBoundFramebuffer(target, GL_STENCIL_ATTACHMENT, textarget, texture, level, 0); |
| - preserveObjectWrapper(scriptState, framebufferBinding, "attachment", GL_DEPTH_ATTACHMENT, texture); |
| - preserveObjectWrapper(scriptState, framebufferBinding, "attachment", GL_STENCIL_ATTACHMENT, texture); |
| + preserveObjectWrapper(scriptState, framebufferBinding, V8HiddenValue::webglAttachments(scriptState->isolate()), framebufferBinding->getPersistentCache(), GL_DEPTH_ATTACHMENT, texture); |
| + preserveObjectWrapper(scriptState, framebufferBinding, V8HiddenValue::webglAttachments(scriptState->isolate()), framebufferBinding->getPersistentCache(), GL_STENCIL_ATTACHMENT, texture); |
| } else { |
| contextGL()->FramebufferTexture2D(target, attachment, textarget, textureObject, level); |
| framebufferBinding->setAttachmentForBoundFramebuffer(target, attachment, textarget, texture, level, 0); |
| - preserveObjectWrapper(scriptState, framebufferBinding, "attachment", attachment, texture); |
| + preserveObjectWrapper(scriptState, framebufferBinding, V8HiddenValue::webglAttachments(scriptState->isolate()), framebufferBinding->getPersistentCache(), attachment, texture); |
| } |
| applyStencilTest(); |
| } |
| @@ -2562,7 +2590,7 @@ ScriptValue WebGLRenderingContextBase::getExtension(ScriptState* scriptState, co |
| if (linkContextToExtension) { |
| // Keep the extension's JavaScript wrapper alive as long as the context is alive, so that |
| // expando properties that are added to the extension persist. |
| - preserveObjectWrapper(scriptState, this, "extension", static_cast<unsigned long>(extension->name()), extension); |
| + preserveObjectWrapper(scriptState, this, V8HiddenValue::webglExtensions(scriptState->isolate()), &m_extensionWrappers, static_cast<uint32_t>(extension->name()), extension); |
| } |
| return ScriptValue(scriptState, wrappedExtension); |
| @@ -4857,7 +4885,7 @@ void WebGLRenderingContextBase::useProgram(ScriptState* scriptState, WebGLProgra |
| contextGL()->UseProgram(objectOrZero(program)); |
| if (program) |
| program->onAttached(); |
| - preserveObjectWrapper(scriptState, this, "program", 0, program); |
| + preserveObjectWrapper(scriptState, this, V8HiddenValue::webglMisc(scriptState->isolate()), &m_miscWrappers, static_cast<uint32_t>(PreservedProgram), program); |
| } |
| } |
| @@ -5020,7 +5048,7 @@ void WebGLRenderingContextBase::vertexAttribPointer(ScriptState* scriptState, GL |
| m_boundVertexArrayObject->setArrayBufferForAttrib(index, m_boundArrayBuffer.get()); |
| contextGL()->VertexAttribPointer(index, size, type, normalized, stride, reinterpret_cast<void*>(static_cast<intptr_t>(offset))); |
| maybePreserveDefaultVAOObjectWrapper(scriptState); |
| - preserveObjectWrapper(scriptState, m_boundVertexArrayObject, "arraybuffer", index, m_boundArrayBuffer); |
| + preserveObjectWrapper(scriptState, m_boundVertexArrayObject, V8HiddenValue::webglBuffers(scriptState->isolate()), m_boundVertexArrayObject->getPersistentCache(), index, m_boundArrayBuffer); |
| } |
| void WebGLRenderingContextBase::vertexAttribDivisorANGLE(GLuint index, GLuint divisor) |
| @@ -6256,36 +6284,32 @@ void WebGLRenderingContextBase::findNewMaxNonDefaultTextureUnit() |
| m_onePlusMaxNonDefaultTextureUnit = 0; |
| } |
| -void WebGLRenderingContextBase::preserveObjectWrapper(ScriptState* scriptState, ScriptWrappable* sourceObject, const char* baseName, unsigned long index, ScriptWrappable* targetObject) |
| +void WebGLRenderingContextBase::preserveObjectWrapper(ScriptState* scriptState, ScriptWrappable* sourceObject, v8::Local<v8::String> hiddenValueName, v8::Persistent<v8::Array>* persistentCache, uint32_t index, ScriptWrappable* targetObject) |
| { |
| - ASSERT(scriptState); |
| - |
| - v8::Local<v8::Value> value; |
| v8::Isolate* isolate = scriptState->isolate(); |
| - |
| - // TODO (kbr): move this logic to V8HiddenValue. The difficulty in doing so is that the index |
| - // may vary, so it'd be necessary to lazily instantiate the V8 internalized strings, and have |
| - // efficient lookup for already-created ones. |
| - StringBuilder builder; |
| - builder.append(baseName); |
| - builder.appendNumber(static_cast<unsigned>(index)); |
| - CString name = builder.toString().utf8(); |
| - v8::Local<v8::String> jsName = v8::String::NewFromUtf8( |
| - isolate, |
| - name.data(), |
| - v8::NewStringType::kNormal, |
| - name.length()).ToLocalChecked(); |
| - if (targetObject) { |
| + if (persistentCache->IsEmpty()) { |
| + persistentCache->Reset(isolate, v8::Array::New(isolate)); |
| V8HiddenValue::setHiddenValue( |
| scriptState, |
| sourceObject->newLocalWrapper(isolate), |
| - jsName, |
| - targetObject->newLocalWrapper(isolate)); |
| + hiddenValueName, |
| + persistentCache->Get(isolate)); |
| + // It is important to mark the persistent cache as weak |
| + // (phantom, actually). Otherwise there will be a reference |
| + // cycle between it and its JavaScript wrapper, and currently |
| + // there are problems collecting such cycles. |
| + persistentCache->SetWeak(); |
| + } |
| + |
| + v8::Local<v8::Array> localCache = persistentCache->Get(isolate); |
| + if (targetObject) { |
| + bool result; |
| + V8_CALL(result, localCache, Set(scriptState->context(), index, targetObject->newLocalWrapper(isolate)), return); |
|
haraken
2016/05/13 04:33:00
v8CallOrCrash
|
| + ASSERT_UNUSED(result, result); |
| } else { |
| - V8HiddenValue::deleteHiddenValue( |
| - scriptState, |
| - sourceObject->newLocalWrapper(isolate), |
| - jsName); |
| + bool result; |
| + V8_CALL(result, localCache, Set(scriptState->context(), index, v8::Null(isolate)), return); |
|
haraken
2016/05/13 04:33:00
v8CallOrCrash
|
| + ASSERT_UNUSED(result, result); |
| } |
| } |
| @@ -6297,7 +6321,7 @@ void WebGLRenderingContextBase::maybePreserveDefaultVAOObjectWrapper(ScriptState |
| // The default VAO does not have a JavaScript wrapper created for it, but one is needed to |
| // link up the WebGLBuffers associated with the vertex attributes. |
| toV8(m_defaultVertexArrayObject, scriptState->context()->Global(), scriptState->isolate()); |
| - preserveObjectWrapper(scriptState, this, "defaultvao", 0, m_defaultVertexArrayObject); |
| + preserveObjectWrapper(scriptState, this, V8HiddenValue::webglMisc(scriptState->isolate()), &m_miscWrappers, static_cast<uint32_t>(PreservedDefaultVAO), m_defaultVertexArrayObject); |
| m_preservedDefaultVAOObjectWrapper = true; |
| } |
| } |