Index: src/bootstrapper.cc |
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc |
index 4bb0f4d0475ea21f6fb4a9cb0b611811800e068b..ba9545c24257bf0a964d5dc4d25c84e6a77f7042 100644 |
--- a/src/bootstrapper.cc |
+++ b/src/bootstrapper.cc |
@@ -167,7 +167,9 @@ class Genesis BASE_EMBEDDED { |
// Creates the empty function. Used for creating a context from scratch. |
Handle<JSFunction> CreateEmptyFunction(Isolate* isolate); |
// Creates the ThrowTypeError function. ECMA 5th Ed. 13.2.3 |
- Handle<JSFunction> GetThrowTypeErrorFunction(); |
+ Handle<JSFunction> GetStrictPoisonFunction(); |
+ // Poison for sloppy generator function arguments/callee. |
+ Handle<JSFunction> GetGeneratorPoisonFunction(); |
void CreateStrictModeFunctionMaps(Handle<JSFunction> empty); |
@@ -302,7 +304,8 @@ class Genesis BASE_EMBEDDED { |
// prototype, maps. |
Handle<Map> sloppy_function_map_writable_prototype_; |
Handle<Map> strict_function_map_writable_prototype_; |
- Handle<JSFunction> throw_type_error_function; |
+ Handle<JSFunction> strict_poison_function; |
+ Handle<JSFunction> generator_poison_function; |
BootstrapperActive active_; |
friend class Bootstrapper; |
@@ -569,19 +572,35 @@ void Genesis::SetStrictFunctionInstanceDescriptor( |
// ECMAScript 5th Edition, 13.2.3 |
-Handle<JSFunction> Genesis::GetThrowTypeErrorFunction() { |
- if (throw_type_error_function.is_null()) { |
+Handle<JSFunction> Genesis::GetStrictPoisonFunction() { |
+ if (strict_poison_function.is_null()) { |
Handle<String> name = factory()->InternalizeOneByteString( |
STATIC_ASCII_VECTOR("ThrowTypeError")); |
Handle<Code> code(isolate()->builtins()->builtin( |
Builtins::kStrictModePoisonPill)); |
- throw_type_error_function = factory()->NewFunction(name, code); |
- throw_type_error_function->set_map(native_context()->sloppy_function_map()); |
- throw_type_error_function->shared()->DontAdaptArguments(); |
+ strict_poison_function = factory()->NewFunction(name, code); |
+ strict_poison_function->set_map(native_context()->sloppy_function_map()); |
+ strict_poison_function->shared()->DontAdaptArguments(); |
- JSObject::PreventExtensions(throw_type_error_function).Assert(); |
+ JSObject::PreventExtensions(strict_poison_function).Assert(); |
} |
- return throw_type_error_function; |
+ return strict_poison_function; |
+} |
+ |
+ |
+Handle<JSFunction> Genesis::GetGeneratorPoisonFunction() { |
+ if (generator_poison_function.is_null()) { |
+ Handle<String> name = factory()->InternalizeOneByteString( |
+ STATIC_ASCII_VECTOR("ThrowTypeError")); |
+ Handle<Code> code(isolate()->builtins()->builtin( |
+ Builtins::kGeneratorPoisonPill)); |
+ generator_poison_function = factory()->NewFunction(name, code); |
+ generator_poison_function->set_map(native_context()->sloppy_function_map()); |
+ generator_poison_function->shared()->DontAdaptArguments(); |
+ |
+ JSObject::PreventExtensions(generator_poison_function).Assert(); |
+ } |
+ return generator_poison_function; |
} |
@@ -633,9 +652,20 @@ static void SetAccessors(Handle<Map> map, |
} |
+static void ReplaceAccessors(Handle<Map> map, |
+ Handle<String> name, |
+ PropertyAttributes attributes, |
+ Handle<AccessorPair> accessor_pair) { |
+ DescriptorArray* descriptors = map->instance_descriptors(); |
+ int idx = descriptors->SearchWithCache(*name, *map); |
+ CallbacksDescriptor descriptor(name, accessor_pair, attributes); |
+ descriptors->Replace(idx, &descriptor); |
+} |
+ |
+ |
void Genesis::PoisonArgumentsAndCaller(Handle<Map> map) { |
- SetAccessors(map, factory()->arguments_string(), GetThrowTypeErrorFunction()); |
- SetAccessors(map, factory()->caller_string(), GetThrowTypeErrorFunction()); |
+ SetAccessors(map, factory()->arguments_string(), GetStrictPoisonFunction()); |
+ SetAccessors(map, factory()->caller_string(), GetStrictPoisonFunction()); |
} |
@@ -1162,14 +1192,13 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global, |
Handle<AccessorPair> callee = factory->NewAccessorPair(); |
Handle<AccessorPair> caller = factory->NewAccessorPair(); |
- Handle<JSFunction> throw_function = |
- GetThrowTypeErrorFunction(); |
+ Handle<JSFunction> poison = GetStrictPoisonFunction(); |
// Install the ThrowTypeError functions. |
- callee->set_getter(*throw_function); |
- callee->set_setter(*throw_function); |
- caller->set_getter(*throw_function); |
- caller->set_setter(*throw_function); |
+ callee->set_getter(*poison); |
+ callee->set_setter(*poison); |
+ caller->set_getter(*poison); |
+ caller->set_setter(*poison); |
// Create the map. Allocate one in-object field for length. |
Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, |
@@ -1366,20 +1395,42 @@ void Genesis::InitializeExperimentalGlobal() { |
// Create maps for generator functions and their prototypes. Store those |
// maps in the native context. |
- Handle<Map> function_map(native_context()->sloppy_function_map()); |
- Handle<Map> generator_function_map = Map::Copy(function_map); |
+ Handle<Map> sloppy_function_map(native_context()->sloppy_function_map()); |
+ Handle<Map> generator_function_map = Map::Copy(sloppy_function_map); |
generator_function_map->set_prototype(*generator_function_prototype); |
native_context()->set_sloppy_generator_function_map( |
*generator_function_map); |
- Handle<Map> strict_mode_function_map( |
- native_context()->strict_function_map()); |
- Handle<Map> strict_mode_generator_function_map = |
- Map::Copy(strict_mode_function_map); |
- strict_mode_generator_function_map->set_prototype( |
- *generator_function_prototype); |
+ // The "arguments" and "caller" instance properties aren't specified, so |
+ // technically we could leave them out. They make even less sense for |
+ // generators than for functions. Still, the same argument that it makes |
+ // sense to keep them around but poisoned in strict mode applies to |
+ // generators as well. With poisoned accessors, naive callers can still |
+ // iterate over the properties without accessing them. |
+ // |
+ // We can't use PoisonArgumentsAndCaller because that mutates accessor pairs |
+ // in place, and the initial state of the generator function map shares the |
+ // accessor pair with sloppy functions. Also the error message should be |
+ // different. Also unhappily, we can't use the API accessors to implement |
+ // poisoning, because API accessors present themselves as data properties, |
+ // not accessor properties, and so getOwnPropertyDescriptor raises an |
+ // exception as it tries to get the values. Sadness. |
+ Handle<AccessorPair> poison_pair(factory()->NewAccessorPair()); |
+ PropertyAttributes rw_attribs = |
+ static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE); |
+ poison_pair->set_getter(*GetGeneratorPoisonFunction()); |
+ poison_pair->set_setter(*GetGeneratorPoisonFunction()); |
+ ReplaceAccessors(generator_function_map, factory()->arguments_string(), |
+ rw_attribs, poison_pair); |
+ ReplaceAccessors(generator_function_map, factory()->caller_string(), |
+ rw_attribs, poison_pair); |
+ |
+ Handle<Map> strict_function_map(native_context()->strict_function_map()); |
+ Handle<Map> strict_generator_function_map = Map::Copy(strict_function_map); |
+ // "arguments" and "caller" already poisoned. |
+ strict_generator_function_map->set_prototype(*generator_function_prototype); |
native_context()->set_strict_generator_function_map( |
- *strict_mode_generator_function_map); |
+ *strict_generator_function_map); |
Handle<JSFunction> object_function(native_context()->object_function()); |
Handle<Map> generator_object_prototype_map = Map::Create( |