Ensure that JSProxy::Fix gives the generated JSObject map a constructor
All JSObjects in V8 either have a map()->constructor() field or are JSFunctions. JSProxy::Fix, however, was not enforcing this, and Object.observe's use of JSObject::GetCreationContext() exposed this. Note that this is not Object.observe-specific: the API call v8::Object::CreationContext() also would have revealed this bug. This patch chooses Object as a reasonable constructor to put on the newly-fixed object's map. Note that this has no effect on the "constructor" property in JS. In doing so, I've also tightened up the code underlying JSProxy::Fix to only support JSObject and JSFunction as possible output types. BUG=405844 LOG=N R=rossberg@chromium.org, verwaest@chromium.org Review URL: https://codereview.chromium.org/505303004 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23466 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
887ba6c133
commit
71fbe7d4ec
@ -1777,20 +1777,19 @@ Handle<JSProxy> Factory::NewJSFunctionProxy(Handle<Object> handler,
|
||||
}
|
||||
|
||||
|
||||
void Factory::ReinitializeJSReceiver(Handle<JSReceiver> object,
|
||||
InstanceType type,
|
||||
int size) {
|
||||
DCHECK(type >= FIRST_JS_OBJECT_TYPE);
|
||||
void Factory::ReinitializeJSProxy(Handle<JSProxy> proxy, InstanceType type,
|
||||
int size) {
|
||||
DCHECK(type == JS_OBJECT_TYPE || type == JS_FUNCTION_TYPE);
|
||||
|
||||
// Allocate fresh map.
|
||||
// TODO(rossberg): Once we optimize proxies, cache these maps.
|
||||
Handle<Map> map = NewMap(type, size);
|
||||
|
||||
// Check that the receiver has at least the size of the fresh object.
|
||||
int size_difference = object->map()->instance_size() - map->instance_size();
|
||||
int size_difference = proxy->map()->instance_size() - map->instance_size();
|
||||
DCHECK(size_difference >= 0);
|
||||
|
||||
map->set_prototype(object->map()->prototype());
|
||||
map->set_prototype(proxy->map()->prototype());
|
||||
|
||||
// Allocate the backing storage for the properties.
|
||||
int prop_size = map->InitialPropertiesLength();
|
||||
@ -1811,24 +1810,31 @@ void Factory::ReinitializeJSReceiver(Handle<JSReceiver> object,
|
||||
|
||||
// Put in filler if the new object is smaller than the old.
|
||||
if (size_difference > 0) {
|
||||
Address address = object->address();
|
||||
Address address = proxy->address();
|
||||
heap->CreateFillerObjectAt(address + map->instance_size(), size_difference);
|
||||
heap->AdjustLiveBytes(address, -size_difference, Heap::FROM_MUTATOR);
|
||||
}
|
||||
|
||||
// Reset the map for the object.
|
||||
object->synchronized_set_map(*map);
|
||||
Handle<JSObject> jsobj = Handle<JSObject>::cast(object);
|
||||
proxy->synchronized_set_map(*map);
|
||||
Handle<JSObject> jsobj = Handle<JSObject>::cast(proxy);
|
||||
|
||||
// Reinitialize the object from the constructor map.
|
||||
heap->InitializeJSObjectFromMap(*jsobj, *properties, *map);
|
||||
|
||||
// The current native context is used to set up certain bits.
|
||||
// TODO(adamk): Using the current context seems wrong, it should be whatever
|
||||
// context the JSProxy originated in. But that context isn't stored anywhere.
|
||||
Handle<Context> context(isolate()->native_context());
|
||||
|
||||
// Functions require some minimal initialization.
|
||||
if (type == JS_FUNCTION_TYPE) {
|
||||
map->set_function_with_prototype(true);
|
||||
Handle<JSFunction> js_function = Handle<JSFunction>::cast(object);
|
||||
Handle<Context> context(isolate()->native_context());
|
||||
Handle<JSFunction> js_function = Handle<JSFunction>::cast(proxy);
|
||||
InitializeFunction(js_function, shared.ToHandleChecked(), context);
|
||||
} else {
|
||||
// Provide JSObjects with a constructor.
|
||||
map->set_constructor(context->object_function());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1866,13 +1872,13 @@ void Factory::ReinitializeJSGlobalProxy(Handle<JSGlobalProxy> object,
|
||||
}
|
||||
|
||||
|
||||
void Factory::BecomeJSObject(Handle<JSReceiver> object) {
|
||||
ReinitializeJSReceiver(object, JS_OBJECT_TYPE, JSObject::kHeaderSize);
|
||||
void Factory::BecomeJSObject(Handle<JSProxy> proxy) {
|
||||
ReinitializeJSProxy(proxy, JS_OBJECT_TYPE, JSObject::kHeaderSize);
|
||||
}
|
||||
|
||||
|
||||
void Factory::BecomeJSFunction(Handle<JSReceiver> object) {
|
||||
ReinitializeJSReceiver(object, JS_FUNCTION_TYPE, JSFunction::kSize);
|
||||
void Factory::BecomeJSFunction(Handle<JSProxy> proxy) {
|
||||
ReinitializeJSProxy(proxy, JS_FUNCTION_TYPE, JSFunction::kSize);
|
||||
}
|
||||
|
||||
|
||||
|
@ -449,13 +449,6 @@ class Factory V8_FINAL {
|
||||
Handle<Object> construct_trap,
|
||||
Handle<Object> prototype);
|
||||
|
||||
// Reinitialize a JSReceiver into an (empty) JS object of respective type and
|
||||
// size, but keeping the original prototype. The receiver must have at least
|
||||
// the size of the new object. The object is reinitialized and behaves as an
|
||||
// object that has been freshly allocated.
|
||||
void ReinitializeJSReceiver(
|
||||
Handle<JSReceiver> object, InstanceType type, int size);
|
||||
|
||||
// Reinitialize an JSGlobalProxy based on a constructor. The object
|
||||
// must have the same size as objects allocated using the
|
||||
// constructor. The object is reinitialized and behaves as an
|
||||
@ -464,8 +457,8 @@ class Factory V8_FINAL {
|
||||
Handle<JSFunction> constructor);
|
||||
|
||||
// Change the type of the argument into a JS object/function and reinitialize.
|
||||
void BecomeJSObject(Handle<JSReceiver> object);
|
||||
void BecomeJSFunction(Handle<JSReceiver> object);
|
||||
void BecomeJSObject(Handle<JSProxy> object);
|
||||
void BecomeJSFunction(Handle<JSProxy> object);
|
||||
|
||||
Handle<JSFunction> NewFunction(Handle<String> name,
|
||||
Handle<Code> code,
|
||||
@ -707,6 +700,12 @@ class Factory V8_FINAL {
|
||||
Handle<JSFunction> NewFunction(Handle<Map> map,
|
||||
Handle<String> name,
|
||||
MaybeHandle<Code> maybe_code);
|
||||
|
||||
// Reinitialize a JSProxy into an (empty) JS object of respective type and
|
||||
// size, but keeping the original prototype. The receiver must have at least
|
||||
// the size of the new object. The object is reinitialized and behaves as an
|
||||
// object that has been freshly allocated.
|
||||
void ReinitializeJSProxy(Handle<JSProxy> proxy, InstanceType type, int size);
|
||||
};
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
13
test/mjsunit/harmony/regress/regress-405844.js
Normal file
13
test/mjsunit/harmony/regress/regress-405844.js
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Flags: --harmony-proxies
|
||||
|
||||
var proxy = Proxy.create({ fix: function() { return {}; } });
|
||||
Object.preventExtensions(proxy);
|
||||
Object.observe(proxy, function(){});
|
||||
|
||||
var functionProxy = Proxy.createFunction({ fix: function() { return {}; } }, function(){});
|
||||
Object.preventExtensions(functionProxy);
|
||||
Object.observe(functionProxy, function(){});
|
Loading…
Reference in New Issue
Block a user