Added ability to remove prototype from function. In this case, [[Construct]] from...
authordgozman@chromium.org <dgozman@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 28 Apr 2010 12:05:40 +0000 (12:05 +0000)
committerdgozman@chromium.org <dgozman@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 28 Apr 2010 12:05:40 +0000 (12:05 +0000)
Added runtime function %FunctionRemovePrototype for this.
Removed prototypes from all builtin functions.
Some sputnik tests marked as fixed.
Added test to check builtins behavior.

Review URL: http://codereview.chromium.org/1722003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4536 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

14 files changed:
src/bootstrapper.cc
src/contexts.h
src/factory.cc
src/factory.h
src/handles.cc
src/ic.cc
src/objects-inl.h
src/objects.cc
src/objects.h
src/runtime.cc
src/runtime.h
src/v8natives.js
test/mjsunit/function-without-prototype.js [new file with mode: 0644]
test/sputnik/sputnik.status

index ac9663d..4f0e0db 100644 (file)
@@ -248,9 +248,13 @@ class Genesis BASE_EMBEDDED {
   void TransferNamedProperties(Handle<JSObject> from, Handle<JSObject> to);
   void TransferIndexedProperties(Handle<JSObject> from, Handle<JSObject> to);
 
+  enum PrototypePropertyMode {
+    DONT_ADD_PROTOTYPE,
+    ADD_READONLY_PROTOTYPE,
+    ADD_WRITEABLE_PROTOTYPE
+  };
   Handle<DescriptorArray> ComputeFunctionInstanceDescriptor(
-      bool make_prototype_read_only,
-      bool make_prototype_enumerable = false);
+      PrototypePropertyMode prototypeMode);
   void MakeFunctionInstancePrototypeWritable();
 
   static bool CompileBuiltin(int index);
@@ -330,7 +334,8 @@ static Handle<JSFunction> InstallFunction(Handle<JSObject> target,
                                           bool is_ecma_native) {
   Handle<String> symbol = Factory::LookupAsciiSymbol(name);
   Handle<Code> call_code = Handle<Code>(Builtins::builtin(call));
-  Handle<JSFunction> function =
+  Handle<JSFunction> function = prototype.is_null() ?
+    Factory::NewFunctionWithoutPrototype(symbol, call_code) :
     Factory::NewFunctionWithPrototype(symbol,
                                       type,
                                       instance_size,
@@ -346,23 +351,23 @@ static Handle<JSFunction> InstallFunction(Handle<JSObject> target,
 
 
 Handle<DescriptorArray> Genesis::ComputeFunctionInstanceDescriptor(
-    bool make_prototype_read_only,
-    bool make_prototype_enumerable) {
+    PrototypePropertyMode prototypeMode) {
   Handle<DescriptorArray> result = Factory::empty_descriptor_array();
 
-  // Add prototype.
-  PropertyAttributes attributes = static_cast<PropertyAttributes>(
-      (make_prototype_enumerable ? 0 : DONT_ENUM)
-      | DONT_DELETE
-      | (make_prototype_read_only ? READ_ONLY : 0));
-  result =
-      Factory::CopyAppendProxyDescriptor(
-          result,
-          Factory::prototype_symbol(),
-          Factory::NewProxy(&Accessors::FunctionPrototype),
-          attributes);
+  if (prototypeMode != DONT_ADD_PROTOTYPE) {
+    PropertyAttributes attributes = static_cast<PropertyAttributes>(
+        DONT_ENUM |
+        DONT_DELETE |
+        (prototypeMode == ADD_READONLY_PROTOTYPE ? READ_ONLY : 0));
+    result =
+        Factory::CopyAppendProxyDescriptor(
+            result,
+            Factory::prototype_symbol(),
+            Factory::NewProxy(&Accessors::FunctionPrototype),
+            attributes);
+  }
 
-  attributes =
+  PropertyAttributes attributes =
       static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
   // Add length.
   result =
@@ -407,14 +412,26 @@ Handle<JSFunction> Genesis::CreateEmptyFunction() {
   // Please note that the prototype property for function instances must be
   // writable.
   Handle<DescriptorArray> function_map_descriptors =
-      ComputeFunctionInstanceDescriptor(false, false);
+      ComputeFunctionInstanceDescriptor(ADD_WRITEABLE_PROTOTYPE);
   fm->set_instance_descriptors(*function_map_descriptors);
+  fm->set_function_with_prototype(true);
+
+  // Functions with this map will not have a 'prototype' property, and
+  // can not be used as constructors.
+  fm = Factory::NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
+  global_context()->set_function_without_prototype_map(*fm);
+  function_map_descriptors =
+      ComputeFunctionInstanceDescriptor(DONT_ADD_PROTOTYPE);
+  fm->set_instance_descriptors(*function_map_descriptors);
+  fm->set_function_with_prototype(false);
 
   // Allocate the function map first and then patch the prototype later
   fm = Factory::NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
   global_context()->set_function_map(*fm);
-  function_map_descriptors = ComputeFunctionInstanceDescriptor(true);
+  function_map_descriptors =
+      ComputeFunctionInstanceDescriptor(ADD_READONLY_PROTOTYPE);
   fm->set_instance_descriptors(*function_map_descriptors);
+  fm->set_function_with_prototype(true);
 
   Handle<String> object_name = Handle<String>(Heap::Object_symbol());
 
@@ -458,6 +475,11 @@ Handle<JSFunction> Genesis::CreateEmptyFunction() {
   global_context()->function_map()->set_prototype(*empty_function);
   global_context()->function_instance_map()->set_prototype(*empty_function);
 
+  // Allocate a distinct prototype for the function map for functions without
+  // prototype, so it will not add 'prototype' property in the proto chain.
+  global_context()->function_without_prototype_map()->set_prototype(
+      *Factory::NewJSObject(Top::object_function(), TENURED));
+
   // Allocate the function map first and then patch the prototype later
   Handle<Map> empty_fm = Factory::CopyMapDropDescriptors(fm);
   empty_fm->set_instance_descriptors(*function_map_descriptors);
@@ -1215,12 +1237,12 @@ bool Genesis::InstallNatives() {
     // Install the call and the apply functions.
     Handle<JSFunction> call =
         InstallFunction(proto, "call", JS_OBJECT_TYPE, JSObject::kHeaderSize,
-                        Factory::NewJSObject(Top::object_function(), TENURED),
+                        Handle<JSObject>::null(),
                         Builtins::FunctionCall,
                         false);
     Handle<JSFunction> apply =
         InstallFunction(proto, "apply", JS_OBJECT_TYPE, JSObject::kHeaderSize,
-                        Factory::NewJSObject(Top::object_function(), TENURED),
+                        Handle<JSObject>::null(),
                         Builtins::FunctionApply,
                         false);
 
@@ -1236,6 +1258,23 @@ bool Genesis::InstallNatives() {
     // Set the lengths for the functions to satisfy ECMA-262.
     call->shared()->set_length(1);
     apply->shared()->set_length(2);
+
+    // Install the call, apply, toString and constructor properties
+    // for the functions without prototype.
+    Handle<JSObject> wp_proto = Handle<JSObject>(
+        JSObject::cast(Top::function_without_prototype_map()->prototype()));
+
+    Handle<String> call_symbol = Factory::LookupAsciiSymbol("call");
+    SetProperty(wp_proto, call_symbol, call, DONT_ENUM);
+
+    Handle<String> apply_symbol = Factory::LookupAsciiSymbol("apply");
+    SetProperty(wp_proto, apply_symbol, apply, DONT_ENUM);
+
+    Handle<Object> to_string = GetProperty(proto, "toString");
+    Handle<String> to_string_symbol = Factory::LookupAsciiSymbol("toString");
+    SetProperty(wp_proto, to_string_symbol, to_string, DONT_ENUM);
+
+    SetProperty(wp_proto, Factory::constructor_symbol(), function, DONT_ENUM);
   }
 
   // Create a constructor for RegExp results (a variant of Array that
@@ -1655,9 +1694,10 @@ void Genesis::MakeFunctionInstancePrototypeWritable() {
   HandleScope scope;
 
   Handle<DescriptorArray> function_map_descriptors =
-      ComputeFunctionInstanceDescriptor(false);
+      ComputeFunctionInstanceDescriptor(ADD_WRITEABLE_PROTOTYPE);
   Handle<Map> fm = Factory::CopyMapDropDescriptors(Top::function_map());
   fm->set_instance_descriptors(*function_map_descriptors);
+  fm->set_function_with_prototype(true);
   Top::context()->global_context()->set_function_map(*fm);
 }
 
index ae9bd76..01bb21b 100644 (file)
@@ -74,6 +74,7 @@ enum ContextLookupFlags {
   V(INSTANTIATE_FUN_INDEX, JSFunction, instantiate_fun) \
   V(CONFIGURE_INSTANCE_FUN_INDEX, JSFunction, configure_instance_fun) \
   V(FUNCTION_MAP_INDEX, Map, function_map) \
+  V(FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, Map, function_without_prototype_map) \
   V(FUNCTION_INSTANCE_MAP_INDEX, Map, function_instance_map) \
   V(JS_ARRAY_MAP_INDEX, Map, js_array_map)\
   V(REGEXP_RESULT_MAP_INDEX, Map, regexp_result_map)\
@@ -179,6 +180,7 @@ class Context: public FixedArray {
     JS_ARRAY_MAP_INDEX,
     REGEXP_RESULT_MAP_INDEX,
     FUNCTION_MAP_INDEX,
+    FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX,
     FUNCTION_INSTANCE_MAP_INDEX,
     INITIAL_OBJECT_PROTOTYPE_INDEX,
     BOOLEAN_FUNCTION_INDEX,
index 20f8261..35d3c54 100644 (file)
@@ -513,6 +513,16 @@ Handle<JSFunction> Factory::NewFunctionWithPrototype(Handle<String> name,
 }
 
 
+Handle<JSFunction> Factory::NewFunctionWithoutPrototype(Handle<String> name,
+                                                        Handle<Code> code) {
+  Handle<JSFunction> function = NewFunctionWithoutPrototype(name);
+  function->set_code(*code);
+  ASSERT(!function->has_initial_map());
+  ASSERT(!function->has_prototype());
+  return function;
+}
+
+
 Handle<Code> Factory::NewCode(const CodeDesc& desc,
                               ZoneScopeInfo* sinfo,
                               Code::Flags flags,
@@ -705,6 +715,24 @@ Handle<JSFunction> Factory::NewFunction(Handle<String> name,
 }
 
 
+Handle<JSFunction> Factory::NewFunctionWithoutPrototypeHelper(
+    Handle<String> name) {
+  Handle<SharedFunctionInfo> function_share = NewSharedFunctionInfo(name);
+  CALL_HEAP_FUNCTION(Heap::AllocateFunction(
+                         *Top::function_without_prototype_map(),
+                         *function_share,
+                         *the_hole_value()),
+                     JSFunction);
+}
+
+
+Handle<JSFunction> Factory::NewFunctionWithoutPrototype(Handle<String> name) {
+  Handle<JSFunction> fun = NewFunctionWithoutPrototypeHelper(name);
+  fun->set_context(Top::context()->global_context());
+  return fun;
+}
+
+
 Handle<Object> Factory::ToObject(Handle<Object> object) {
   CALL_HEAP_FUNCTION(object->ToObject(), Object);
 }
index 0f2ae86..8a190fa 100644 (file)
@@ -218,6 +218,8 @@ class Factory : public AllStatic {
   static Handle<JSFunction> NewFunction(Handle<String> name,
                                         Handle<Object> prototype);
 
+  static Handle<JSFunction> NewFunctionWithoutPrototype(Handle<String> name);
+
   static Handle<JSFunction> NewFunction(Handle<Object> super, bool is_global);
 
   static Handle<JSFunction> BaseNewFunctionFromSharedFunctionInfo(
@@ -291,6 +293,9 @@ class Factory : public AllStatic {
                                                      Handle<Code> code,
                                                      bool force_initial_map);
 
+  static Handle<JSFunction> NewFunctionWithoutPrototype(Handle<String> name,
+                                                        Handle<Code> code);
+
   static Handle<DescriptorArray> CopyAppendProxyDescriptor(
       Handle<DescriptorArray> array,
       Handle<String> key,
@@ -376,6 +381,9 @@ class Factory : public AllStatic {
   static Handle<JSFunction> NewFunctionHelper(Handle<String> name,
                                               Handle<Object> prototype);
 
+  static Handle<JSFunction> NewFunctionWithoutPrototypeHelper(
+      Handle<String> name);
+
   static Handle<DescriptorArray> CopyAppendCallbackDescriptors(
       Handle<DescriptorArray> array,
       Handle<Object> descriptors);
index 84ee20b..1d4465f 100644 (file)
@@ -203,6 +203,7 @@ void FlattenString(Handle<String> string) {
 
 Handle<Object> SetPrototype(Handle<JSFunction> function,
                             Handle<Object> prototype) {
+  ASSERT(function->should_have_prototype());
   CALL_HEAP_FUNCTION(Accessors::FunctionSetPrototype(*function,
                                                      *prototype,
                                                      NULL),
index eaa0554..64c3ec1 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -615,7 +615,8 @@ Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) {
     }
 
     // Use specialized code for getting prototype of functions.
-    if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol())) {
+    if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol()) &&
+        JSFunction::cast(*object)->should_have_prototype()) {
 #ifdef DEBUG
       if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
 #endif
@@ -824,7 +825,8 @@ Object* KeyedLoadIC::Load(State state,
       }
 
       // Use specialized code for getting prototype of functions.
-      if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol())) {
+      if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol()) &&
+        JSFunction::cast(*object)->should_have_prototype()) {
         Handle<JSFunction> function = Handle<JSFunction>::cast(object);
         Object* code =
             StubCache::ComputeKeyedLoadFunctionPrototype(*name, *function);
index 621a3f8..59fdd86 100644 (file)
@@ -2113,6 +2113,20 @@ bool Map::has_non_instance_prototype() {
 }
 
 
+void Map::set_function_with_prototype(bool value) {
+  if (value) {
+    set_bit_field2(bit_field2() | (1 << kFunctionWithPrototype));
+  } else {
+    set_bit_field2(bit_field2() & ~(1 << kFunctionWithPrototype));
+  }
+}
+
+
+bool Map::function_with_prototype() {
+  return ((1 << kFunctionWithPrototype) & bit_field2()) != 0;
+}
+
+
 void Map::set_is_access_check_needed(bool access_check_needed) {
   if (access_check_needed) {
     set_bit_field(bit_field() | (1 << kIsAccessCheckNeeded));
@@ -2568,6 +2582,10 @@ Object* JSFunction::prototype() {
   return instance_prototype();
 }
 
+bool JSFunction::should_have_prototype() {
+  return map()->function_with_prototype();
+}
+
 
 bool JSFunction::is_compiled() {
   return shared()->is_compiled();
index 252d847..459c8aa 100644 (file)
@@ -4906,6 +4906,7 @@ Object* JSFunction::SetInstancePrototype(Object* value) {
 
 
 Object* JSFunction::SetPrototype(Object* value) {
+  ASSERT(should_have_prototype());
   Object* construct_prototype = value;
 
   // If the value is not a JSObject, store the value in the map's
@@ -4931,6 +4932,14 @@ Object* JSFunction::SetPrototype(Object* value) {
 }
 
 
+Object* JSFunction::RemovePrototype() {
+  ASSERT(map() == context()->global_context()->function_map());
+  set_map(context()->global_context()->function_without_prototype_map());
+  set_prototype_or_initial_map(Heap::the_hole_value());
+  return this;
+}
+
+
 Object* JSFunction::SetInstanceClassName(String* name) {
   shared()->set_instance_class_name(name);
   return this;
index cdc2491..40be3a2 100644 (file)
@@ -2854,6 +2854,12 @@ class Map: public HeapObject {
   inline void set_non_instance_prototype(bool value);
   inline bool has_non_instance_prototype();
 
+  // Tells whether function has special prototype property. If not, prototype
+  // property will not be created when accessed (will return undefined),
+  // and construction from this function will not be allowed.
+  inline void set_function_with_prototype(bool value);
+  inline bool function_with_prototype();
+
   // Tells whether the instance with this map should be ignored by the
   // __proto__ accessor.
   inline void set_is_hidden_prototype() {
@@ -3030,6 +3036,7 @@ class Map: public HeapObject {
 
   // Bit positions for bit field 2
   static const int kIsExtensible = 0;
+  static const int kFunctionWithPrototype = 1;
 
   // Layout of the default cache. It holds alternating name and code objects.
   static const int kCodeCacheEntrySize = 2;
@@ -3396,6 +3403,11 @@ class JSFunction: public JSObject {
   Object* SetInstancePrototype(Object* value);
   Object* SetPrototype(Object* value);
 
+  // After prototype is removed, it will not be created when accessed, and
+  // [[Construct]] from this function will not be allowed.
+  Object* RemovePrototype();
+  inline bool should_have_prototype();
+
   // Accessor for this function's initial map's [[class]]
   // property. This is primarily used by ECMA native functions.  This
   // method sets the class_name field of this function's initial map
index 9b9acae..3fa41e9 100644 (file)
@@ -1450,6 +1450,18 @@ static Object* Runtime_FunctionSetName(Arguments args) {
 }
 
 
+static Object* Runtime_FunctionRemovePrototype(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_CHECKED(JSFunction, f, args[0]);
+  Object* obj = f->RemovePrototype();
+  if (obj->IsFailure()) return obj;
+
+  return Heap::undefined_value();
+}
+
+
 static Object* Runtime_FunctionGetScript(Arguments args) {
   HandleScope scope;
   ASSERT(args.length() == 1);
@@ -1523,6 +1535,7 @@ static Object* Runtime_FunctionSetPrototype(Arguments args) {
   ASSERT(args.length() == 2);
 
   CONVERT_CHECKED(JSFunction, fun, args[0]);
+  ASSERT(fun->should_have_prototype());
   Object* obj = Accessors::FunctionSetPrototype(fun, args[1], NULL);
   if (obj->IsFailure()) return obj;
   return args[0];  // return TOS
@@ -6541,6 +6554,16 @@ static Object* Runtime_NewObject(Arguments args) {
   }
 
   Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
+
+  // If function should not have prototype, construction is not allowed. In this
+  // case generated code bailouts here, since function has no initial_map.
+  if (!function->should_have_prototype()) {
+    Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
+    Handle<Object> type_error =
+        Factory::NewTypeError("not_constructor", arguments);
+    return Top::Throw(*type_error);
+  }
+
 #ifdef ENABLE_DEBUGGER_SUPPORT
   // Handle stepping into constructors if step into is active.
   if (Debug::StepInActive()) {
index 02df58d..d0719f6 100644 (file)
@@ -184,6 +184,7 @@ namespace internal {
   F(FunctionSetPrototype, 2, 1) \
   F(FunctionGetName, 1, 1) \
   F(FunctionSetName, 2, 1) \
+  F(FunctionRemovePrototype, 1, 1) \
   F(FunctionGetSourceCode, 1, 1) \
   F(FunctionGetScript, 1, 1) \
   F(FunctionGetScriptSourcePosition, 1, 1) \
index 86d3ad8..fd86dda 100644 (file)
@@ -54,6 +54,7 @@ function InstallFunctions(object, attributes, functions) {
     var key = functions[i];
     var f = functions[i + 1];
     %FunctionSetName(f, key);
+    %FunctionRemovePrototype(f);
     %SetProperty(object, key, f, attributes);
   }
   %ToFastProperties(object);
diff --git a/test/mjsunit/function-without-prototype.js b/test/mjsunit/function-without-prototype.js
new file mode 100644 (file)
index 0000000..9018086
--- /dev/null
@@ -0,0 +1,54 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Tests that function does not have prototype.
+function testPrototype(f) {
+  assertFalse('prototype' in f);
+  assertEquals(undefined, f.prototype);
+  f.prototype = 42;
+  assertEquals(42, f.prototype);
+  assertTrue('prototype' in f);
+}
+
+// Tests that construction from function throws.
+function testConstruction(name) {
+  assertThrows("new " + name + "()");
+  eval(name + ".prototype = 42;");
+  assertThrows("new " + name + "()");
+}
+
+testPrototype(eval);
+testPrototype(Array.prototype.push);
+testPrototype(Function.prototype.call);
+testPrototype(String.fromCharCode);
+var date = new Date();
+testPrototype(date.toString);
+
+testConstruction("parseInt");
+testConstruction("Function.prototype.apply");
+var regexp = /abc/g;
+testConstruction("regexp.test");
index e5b9e20..4c6fd1e 100644 (file)
@@ -54,79 +54,6 @@ S15.10.6.3_A1_T16: FAIL_OK
 S15.10.7_A1_T1: FAIL_OK
 S15.10.7_A1_T2: FAIL_OK
 
-# We allow construct calls to built-in functions, and we allow built-in
-# functions to have prototypes.
-S15.1.2.1_A4.6: FAIL_OK
-S15.1.2.1_A4.7: FAIL_OK
-S15.1.2.2_A9.6: FAIL_OK
-S15.1.2.2_A9.7: FAIL_OK
-S15.1.2.3_A7.6: FAIL_OK
-S15.1.2.3_A7.7: FAIL_OK
-S15.1.2.4_A2.6: FAIL_OK
-S15.1.2.4_A2.7: FAIL_OK
-S15.1.2.5_A2.6: FAIL_OK
-S15.1.2.5_A2.7: FAIL_OK
-S15.1.3.1_A5.6: FAIL_OK
-S15.1.3.1_A5.7: FAIL_OK
-S15.1.3.2_A5.6: FAIL_OK
-S15.1.3.2_A5.7: FAIL_OK
-S15.1.3.3_A5.6: FAIL_OK
-S15.1.3.3_A5.7: FAIL_OK
-S15.1.3.4_A5.6: FAIL_OK
-S15.1.3.4_A5.7: FAIL_OK
-S15.10.6.2_A6: FAIL_OK
-S15.10.6.3_A6: FAIL_OK
-S15.10.6.4_A6: FAIL_OK
-S15.10.6.4_A7: FAIL_OK
-S15.2.4.2_A6: FAIL_OK
-S15.2.4.3_A6: FAIL_OK
-S15.2.4.4_A6: FAIL_OK
-S15.2.4.5_A6: FAIL_OK
-S15.2.4.6_A6: FAIL_OK
-S15.2.4.7_A6: FAIL_OK
-S15.3.4.2_A6: FAIL_OK
-S15.4.4.10_A5.6: FAIL_OK
-S15.4.4.10_A5.7: FAIL_OK
-S15.4.4.11_A7.6: FAIL_OK
-S15.4.4.11_A7.7: FAIL_OK
-S15.4.4.12_A5.6: FAIL_OK
-S15.4.4.12_A5.7: FAIL_OK
-S15.4.4.13_A5.6: FAIL_OK
-S15.4.4.13_A5.7: FAIL_OK
-S15.4.4.2_A4.6: FAIL_OK
-S15.4.4.3_A4.6: FAIL_OK
-S15.4.4.3_A4.6: FAIL_OK
-S15.4.4.4_A4.6: FAIL_OK
-S15.4.4.4_A4.7: FAIL_OK
-S15.4.4.5_A6.6: FAIL_OK
-S15.4.4.5_A6.7: FAIL_OK
-S15.4.4.6_A5.6: FAIL_OK
-S15.4.4.6_A5.7: FAIL_OK
-S15.4.4.7_A6.6: FAIL_OK
-S15.4.4.7_A6.7: FAIL_OK
-S15.4.4.8_A5.6: FAIL_OK
-S15.4.4.8_A5.7: FAIL_OK
-S15.4.4.9_A5.6: FAIL_OK
-S15.4.4.9_A5.7: FAIL_OK
-S15.5.4.10_A6: FAIL_OK
-S15.5.4.11_A6: FAIL_OK
-S15.5.4.12_A6: FAIL_OK
-S15.5.4.13_A6: FAIL_OK
-S15.5.4.14_A6: FAIL_OK
-S15.5.4.15_A6: FAIL_OK
-S15.5.4.16_A6: FAIL_OK
-S15.5.4.17_A6: FAIL_OK
-S15.5.4.18_A6: FAIL_OK
-S15.5.4.19_A6: FAIL_OK
-S15.5.4.4_A6: FAIL_OK
-S15.5.4.5_A6: FAIL_OK
-S15.5.4.6_A6: FAIL_OK
-S15.5.4.7_A6: FAIL_OK
-S15.5.4.9_A6: FAIL_OK
-S15.3.4.3_A12: FAIL_OK
-S15.3.4.4_A12: FAIL_OK
-S15.5.4.8_A6: FAIL_OK
-
 # We are silent in some regexp cases where the spec wants us to give
 # errors, for compatibility.
 S15.10.2.11_A1_T2: FAIL