Revision: 12264
Author: [email protected]
Date: Mon Aug 6 07:25:19 2012
Log: Improve load IC so it can call a native accessor even if the
holder is
in dictionary mode. Add a flag to all maps to indicate whether they are
used for dictionary (normalized) objects or fast mode objects.
Review URL: https://chromiumcodereview.appspot.com/10831153
http://code.google.com/p/v8/source/detail?r=12264
Modified:
/branches/bleeding_edge/src/arm/stub-cache-arm.cc
/branches/bleeding_edge/src/bootstrapper.cc
/branches/bleeding_edge/src/heap.cc
/branches/bleeding_edge/src/hydrogen-instructions.cc
/branches/bleeding_edge/src/hydrogen.cc
/branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
/branches/bleeding_edge/src/ic.cc
/branches/bleeding_edge/src/objects-inl.h
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/src/objects.h
/branches/bleeding_edge/src/stub-cache.h
/branches/bleeding_edge/src/type-info.cc
/branches/bleeding_edge/src/x64/stub-cache-x64.cc
/branches/bleeding_edge/test/cctest/test-api.cc
=======================================
--- /branches/bleeding_edge/src/arm/stub-cache-arm.cc Wed Jul 25 08:26:16
2012
+++ /branches/bleeding_edge/src/arm/stub-cache-arm.cc Mon Aug 6 07:25:19
2012
@@ -1228,6 +1228,42 @@
__ LoadHeapObject(r0, value);
__ Ret();
}
+
+
+void StubCompiler::GenerateDictionaryLoadCallback(Register receiver,
+ Register name_reg,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Handle<AccessorInfo>
callback,
+ Handle<String> name,
+ Label* miss) {
+ Register dictionary = scratch1;
+ Register index = scratch2;
+ __ ldr(dictionary, FieldMemOperand(receiver,
JSObject::kPropertiesOffset));
+
+ // Probe the dictionary.
+ Label probe_done;
+ StringDictionaryLookupStub::GeneratePositiveLookup(masm(),
+ miss,
+ &probe_done,
+ dictionary,
+ name_reg,
+ index, // Set if we
hit.
+ scratch3);
+ __ bind(&probe_done);
+
+ // If probing finds an entry in the dictionary, check that the value is
the
+ // callback.
+ const int kElementsStartOffset =
+ StringDictionary::kHeaderSize +
+ StringDictionary::kElementsStartIndex * kPointerSize;
+ const int kValueOffset = kElementsStartOffset + kPointerSize;
+ __ add(scratch1, dictionary, Operand(kValueOffset - kHeapObjectTag));
+ __ ldr(scratch3, MemOperand(scratch1, index, LSL, kPointerSizeLog2));
+ __ cmp(scratch3, Operand(callback));
+ __ b(ne, miss);
+}
void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
@@ -1247,6 +1283,11 @@
Register reg = CheckPrototypes(object, receiver, holder, scratch1,
scratch2, scratch3, name, miss);
+ if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
+ GenerateDictionaryLoadCallback(
+ receiver, name_reg, scratch1, scratch2, scratch3, callback, name,
miss);
+ }
+
// Build AccessorInfo::args_ list on the stack and push property name
below
// the exit frame to make GC aware of them and store pointers to them.
__ push(receiver);
=======================================
--- /branches/bleeding_edge/src/bootstrapper.cc Mon Jul 23 09:18:25 2012
+++ /branches/bleeding_edge/src/bootstrapper.cc Mon Aug 6 07:25:19 2012
@@ -747,6 +747,7 @@
}
js_global_function->initial_map()->set_is_hidden_prototype();
+ js_global_function->initial_map()->set_dictionary_map(true);
Handle<GlobalObject> inner_global =
factory()->NewGlobalObject(js_global_function);
if (inner_global_out != NULL) {
@@ -1431,6 +1432,7 @@
Handle<String> name = factory()->LookupAsciiSymbol("builtins");
builtins_fun->shared()->set_instance_class_name(*name);
+ builtins_fun->initial_map()->set_dictionary_map(true);
// Allocate the builtins object.
Handle<JSBuiltinsObject> builtins =
=======================================
--- /branches/bleeding_edge/src/heap.cc Mon Aug 6 06:49:13 2012
+++ /branches/bleeding_edge/src/heap.cc Mon Aug 6 07:25:19 2012
@@ -2424,6 +2424,7 @@
if (!maybe_obj->ToObject(&obj)) return false;
}
Map* global_context_map = Map::cast(obj);
+ global_context_map->set_dictionary_map(true);
global_context_map->set_visitor_id(StaticVisitorBase::kVisitGlobalContext);
set_global_context_map(global_context_map);
@@ -4108,6 +4109,7 @@
MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) {
ASSERT(constructor->has_initial_map());
Map* map = constructor->initial_map();
+ ASSERT(map->is_dictionary_map());
// Make sure no field properties are described in the initial map.
// This guarantees us that normalizing the properties does not
@@ -4158,6 +4160,7 @@
Map* new_map;
MaybeObject* maybe_map = map->CopyDropDescriptors();
if (!maybe_map->To(&new_map)) return maybe_map;
+ new_map->set_dictionary_map(true);
// Set up the global object as a normalized object.
global->set_map(new_map);
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.cc Mon Aug 6
07:13:09 2012
+++ /branches/bleeding_edge/src/hydrogen-instructions.cc Mon Aug 6
07:25:19 2012
@@ -1743,6 +1743,10 @@
break;
}
} else if (lookup.IsCacheable() &&
+ // For dicts the lookup on the map will fail, but the
object may
+ // contain the property so we cannot generate a negative
lookup
+ // (which would just be a map check and return undefined).
+ !map->is_dictionary_map() &&
PrototypeChainCanNeverResolve(map, name)) {
negative_lookups.Add(types->at(i), zone);
}
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Mon Aug 6 07:13:09 2012
+++ /branches/bleeding_edge/src/hydrogen.cc Mon Aug 6 07:25:19 2012
@@ -5215,8 +5215,13 @@
HInstruction* instr = NULL;
SmallMapList* types = expr->GetReceiverTypes();
- if (expr->IsMonomorphic()) {
- Handle<Map> map = types->first();
+ bool monomorphic = expr->IsMonomorphic();
+ Handle<Map> map;
+ if (monomorphic) {
+ map = types->first();
+ if (map->is_dictionary_map()) monomorphic = false;
+ }
+ if (monomorphic) {
Handle<AccessorPair> accessors;
Handle<JSObject> holder;
if (LookupAccessorPair(map, name, &accessors, &holder)) {
@@ -5392,8 +5397,14 @@
Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
Handle<Map> map;
HInstruction* load;
- if (prop->IsMonomorphic()) {
+ bool monomorphic = prop->IsMonomorphic();
+ if (monomorphic) {
map = prop->GetReceiverTypes()->first();
+ // We can't generate code for a monomorphic dict mode load so
+ // just pretend it is not monomorphic.
+ if (map->is_dictionary_map()) monomorphic = false;
+ }
+ if (monomorphic) {
Handle<AccessorPair> accessors;
Handle<JSObject> holder;
if (LookupAccessorPair(map, name, &accessors, &holder)) {
@@ -5416,7 +5427,7 @@
if (instr->HasObservableSideEffects()) AddSimulate(operation->id());
HInstruction* store;
- if (map.is_null()) {
+ if (!monomorphic) {
// If we don't know the monomorphic type, do a generic store.
CHECK_ALIVE(store = BuildStoreNamedGeneric(object, name, instr));
} else {
@@ -5717,6 +5728,7 @@
Property* expr,
Handle<Map> map) {
// Handle a load from a known field.
+ ASSERT(!map->is_dictionary_map());
LookupResult lookup(isolate());
map->LookupDescriptor(NULL, *name, &lookup);
if (lookup.IsField()) {
@@ -6350,8 +6362,13 @@
Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
SmallMapList* types = expr->GetReceiverTypes();
+ bool monomorphic = expr->IsMonomorphic();
+ Handle<Map> map;
if (expr->IsMonomorphic()) {
- Handle<Map> map = types->first();
+ map = types->first();
+ if (map->is_dictionary_map()) monomorphic = false;
+ }
+ if (monomorphic) {
Handle<AccessorPair> accessors;
Handle<JSObject> holder;
if (LookupAccessorPair(map, name, &accessors, &holder)) {
@@ -7860,8 +7877,12 @@
Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
Handle<Map> map;
HInstruction* load;
- if (prop->IsMonomorphic()) {
+ bool monomorphic = prop->IsMonomorphic();
+ if (monomorphic) {
map = prop->GetReceiverTypes()->first();
+ if (map->is_dictionary_map()) monomorphic = false;
+ }
+ if (monomorphic) {
Handle<AccessorPair> accessors;
Handle<JSObject> holder;
if (LookupAccessorPair(map, name, &accessors, &holder)) {
@@ -7879,7 +7900,7 @@
input = Pop();
HInstruction* store;
- if (map.is_null()) {
+ if (!monomorphic) {
// If we don't know the monomorphic type, do a generic store.
CHECK_ALIVE(store = BuildStoreNamedGeneric(object, name, after));
} else {
=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Wed Jul 4 04:40:51
2012
+++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Mon Aug 6 07:25:19
2012
@@ -1050,6 +1050,42 @@
GenerateFastPropertyLoad(masm(), eax, reg, holder, index);
__ ret(0);
}
+
+
+void StubCompiler::GenerateDictionaryLoadCallback(Register receiver,
+ Register name_reg,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Handle<AccessorInfo>
callback,
+ Handle<String> name,
+ Label* miss) {
+ Register dictionary = scratch1;
+ __ mov(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset));
+
+ // Probe the dictionary.
+ Label probe_done;
+ StringDictionaryLookupStub::GeneratePositiveLookup(masm(),
+ miss,
+ &probe_done,
+ dictionary,
+ name_reg,
+ scratch2,
+ scratch3);
+ __ bind(&probe_done);
+
+ // If probing finds an entry in the dictionary, scratch2 contains the
+ // index into the dictionary. Check that the value is the callback.
+ Register index = scratch2;
+ const int kElementsStartOffset =
+ StringDictionary::kHeaderSize +
+ StringDictionary::kElementsStartIndex * kPointerSize;
+ const int kValueOffset = kElementsStartOffset + kPointerSize;
+ __ mov(scratch3,
+ Operand(dictionary, index, times_4, kValueOffset -
kHeapObjectTag));
+ __ cmp(scratch3, callback);
+ __ j(not_equal, miss);
+}
void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
@@ -1069,6 +1105,11 @@
Register reg = CheckPrototypes(object, receiver, holder, scratch1,
scratch2, scratch3, name, miss);
+ if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
+ GenerateDictionaryLoadCallback(
+ receiver, name_reg, scratch1, scratch2, scratch3, callback, name,
miss);
+ }
+
// Insert additional parameters into the stack frame above return
address.
ASSERT(!scratch3.is(reg));
__ pop(scratch3); // Get return address to place it below.
=======================================
--- /branches/bleeding_edge/src/ic.cc Wed Aug 1 05:35:33 2012
+++ /branches/bleeding_edge/src/ic.cc Mon Aug 6 07:25:19 2012
@@ -989,7 +989,6 @@
if (callback->IsAccessorInfo()) {
Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(callback);
if (v8::ToCData<Address>(info->getter()) == 0) return;
- if (!holder->HasFastProperties()) return;
if (!info->IsCompatibleReceiver(*receiver)) return;
code = isolate()->stub_cache()->ComputeLoadCallback(
name, receiver, holder, info);
@@ -997,7 +996,6 @@
Handle<Object>
getter(Handle<AccessorPair>::cast(callback)->getter());
if (!getter->IsJSFunction()) return;
if (holder->IsGlobalObject()) return;
- if (!holder->HasFastProperties()) return;
code = isolate()->stub_cache()->ComputeLoadViaGetter(
name, receiver, holder, Handle<JSFunction>::cast(getter));
} else {
=======================================
--- /branches/bleeding_edge/src/objects-inl.h Mon Aug 6 07:13:09 2012
+++ /branches/bleeding_edge/src/objects-inl.h Mon Aug 6 07:25:19 2012
@@ -1608,6 +1608,7 @@
bool JSObject::HasFastProperties() {
+ ASSERT(properties()->IsDictionary() == map()->is_dictionary_map());
return !properties()->IsDictionary();
}
@@ -3006,10 +3007,21 @@
void Map::set_is_shared(bool value) {
set_bit_field3(IsShared::update(bit_field3(), value));
}
+
bool Map::is_shared() {
return IsShared::decode(bit_field3());
}
+
+
+void Map::set_dictionary_map(bool value) {
+ set_bit_field3(DictionaryMap::update(bit_field3(), value));
+}
+
+
+bool Map::is_dictionary_map() {
+ return DictionaryMap::decode(bit_field3());
+}
JSFunction* Map::unchecked_constructor() {
=======================================
--- /branches/bleeding_edge/src/objects.cc Mon Aug 6 07:13:09 2012
+++ /branches/bleeding_edge/src/objects.cc Mon Aug 6 07:25:19 2012
@@ -516,6 +516,7 @@
MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
+ ASSERT(new_map->is_dictionary_map());
set_map(new_map);
}
JSGlobalPropertyCell* cell =
@@ -3218,6 +3219,7 @@
fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
+ ASSERT(Map::cast(result)->is_dictionary_map());
set(index, result);
isolate->counters()->normalized_maps()->Increment();
@@ -3343,6 +3345,7 @@
current_heap->isolate()->context()->global_context()->
normalized_map_cache()->Get(this, mode);
if (!maybe_map->To(&new_map)) return maybe_map;
+ ASSERT(new_map->is_dictionary_map());
// We have now successfully allocated all the necessary objects.
// Changes can now be made with the guarantee that all of them take
effect.
@@ -4512,6 +4515,7 @@
Map* new_map;
MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
+ ASSERT(new_map->is_dictionary_map());
set_map(new_map);
// When running crankshaft, changing the map is not enough. We
@@ -4873,6 +4877,7 @@
result->set_code_cache(code_cache());
result->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
+ result->set_dictionary_map(true);
#ifdef DEBUG
if (FLAG_verify_heap && result->is_shared()) {
@@ -7330,7 +7335,8 @@
bit_field2() == other->bit_field2() &&
static_cast<uint32_t>(bit_field3()) ==
LastAddedBits::update(
- IsShared::update(other->bit_field3(), true),
+ IsShared::update(DictionaryMap::update(other->bit_field3(),
true),
+ true),
kNoneAdded);
}
@@ -12572,6 +12578,7 @@
Map* new_map;
MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
+ new_map->set_dictionary_map(false);
if (instance_descriptor_length == 0) {
ASSERT_LE(unused_property_fields, inobject_props);
=======================================
--- /branches/bleeding_edge/src/objects.h Mon Aug 6 07:13:09 2012
+++ /branches/bleeding_edge/src/objects.h Mon Aug 6 07:25:19 2012
@@ -4699,7 +4699,8 @@
class IsShared: public BitField<bool, 0, 1> {};
class FunctionWithPrototype: public BitField<bool, 1, 1> {};
- class LastAddedBits: public BitField<int, 2, 11> {};
+ class DictionaryMap: public BitField<bool, 2, 1> {};
+ class LastAddedBits: public BitField<int, 3, 11> {};
// Tells whether the object in the prototype property will be used
// for instances created from this function. If the prototype
@@ -4845,6 +4846,13 @@
inline void set_is_shared(bool value);
inline bool is_shared();
+ // Tells whether the map is used for JSObjects in dictionary mode (ie
+ // normalized objects, ie objects for which HasFastProperties returns
false).
+ // A map can never be used for both dictionary mode and fast mode
JSObjects.
+ // False by default and for HeapObjects that are not JSObjects.
+ inline void set_dictionary_map(bool value);
+ inline bool is_dictionary_map();
+
// Tells whether the instance needs security checks when accessing its
// properties.
inline void set_is_access_check_needed(bool access_check_needed);
@@ -5165,6 +5173,7 @@
// Bit positions for bit field 3
static const int kIsShared = 0;
static const int kFunctionWithPrototype = 1;
+ static const int kDictionaryMap = 2;
typedef FixedBodyDescriptor<kPointerFieldsBeginOffset,
kPointerFieldsEndOffset,
=======================================
--- /branches/bleeding_edge/src/stub-cache.h Wed Jul 4 04:40:51 2012
+++ /branches/bleeding_edge/src/stub-cache.h Mon Aug 6 07:25:19 2012
@@ -554,6 +554,15 @@
Handle<String> name,
Label* miss);
+ void GenerateDictionaryLoadCallback(Register receiver,
+ Register name_reg,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Handle<AccessorInfo> callback,
+ Handle<String> name,
+ Label* miss);
+
void GenerateLoadConstant(Handle<JSObject> object,
Handle<JSObject> holder,
Register receiver,
=======================================
--- /branches/bleeding_edge/src/type-info.cc Mon Aug 6 07:13:09 2012
+++ /branches/bleeding_edge/src/type-info.cc Mon Aug 6 07:25:19 2012
@@ -100,11 +100,12 @@
if (map_or_code->IsMap()) return true;
if (map_or_code->IsCode()) {
Handle<Code> code = Handle<Code>::cast(map_or_code);
- return code->is_keyed_load_stub() &&
+ bool preliminary_checks = code->is_keyed_load_stub() &&
code->ic_state() == MONOMORPHIC &&
- Code::ExtractTypeFromFlags(code->flags()) == Code::NORMAL &&
- code->FindFirstMap() != NULL &&
- !CanRetainOtherContext(code->FindFirstMap(), *global_context_);
+ Code::ExtractTypeFromFlags(code->flags()) == Code::NORMAL;
+ if (!preliminary_checks) return false;
+ Map* map = code->FindFirstMap();
+ return map != NULL && !CanRetainOtherContext(map, *global_context_);
}
return false;
}
@@ -131,12 +132,14 @@
bool allow_growth =
Code::GetKeyedAccessGrowMode(code->extra_ic_state()) ==
ALLOW_JSARRAY_GROWTH;
- return code->is_keyed_store_stub() &&
+ bool preliminary_checks =
+ code->is_keyed_store_stub() &&
!allow_growth &&
code->ic_state() == MONOMORPHIC &&
- Code::ExtractTypeFromFlags(code->flags()) == Code::NORMAL &&
- code->FindFirstMap() != NULL &&
- !CanRetainOtherContext(code->FindFirstMap(), *global_context_);
+ Code::ExtractTypeFromFlags(code->flags()) == Code::NORMAL;
+ if (!preliminary_checks) return false;
+ Map* map = code->FindFirstMap();
+ return map != NULL && !CanRetainOtherContext(map, *global_context_);
}
return false;
}
=======================================
--- /branches/bleeding_edge/src/x64/stub-cache-x64.cc Wed Jul 4 04:40:51
2012
+++ /branches/bleeding_edge/src/x64/stub-cache-x64.cc Mon Aug 6 07:25:19
2012
@@ -1027,6 +1027,43 @@
GenerateFastPropertyLoad(masm(), rax, reg, holder, index);
__ ret(0);
}
+
+
+void StubCompiler::GenerateDictionaryLoadCallback(Register receiver,
+ Register name_reg,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Handle<AccessorInfo>
callback,
+ Handle<String> name,
+ Label* miss) {
+ Register dictionary = scratch1;
+ __ movq(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset));
+
+ // Probe the dictionary.
+ Label probe_done;
+ StringDictionaryLookupStub::GeneratePositiveLookup(masm(),
+ miss,
+ &probe_done,
+ dictionary,
+ name_reg,
+ scratch2,
+ scratch3);
+ __ bind(&probe_done);
+
+ // If probing finds an entry in the dictionary, scratch2 contains the
+ // index into the dictionary. Check that the value is the callback.
+ Register index = scratch2;
+ const int kElementsStartOffset =
+ StringDictionary::kHeaderSize +
+ StringDictionary::kElementsStartIndex * kPointerSize;
+ const int kValueOffset = kElementsStartOffset + kPointerSize;
+ __ movq(scratch3,
+ Operand(dictionary, index, times_8, kValueOffset -
kHeapObjectTag));
+ __ movq(scratch2, callback, RelocInfo::EMBEDDED_OBJECT);
+ __ cmpq(scratch3, scratch2);
+ __ j(not_equal, miss);
+}
void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
@@ -1046,6 +1083,11 @@
Register reg = CheckPrototypes(object, receiver, holder, scratch1,
scratch2, scratch3, name, miss);
+ if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
+ GenerateDictionaryLoadCallback(
+ receiver, name_reg, scratch1, scratch2, scratch3, callback, name,
miss);
+ }
+
// Insert additional parameters into the stack frame above return
address.
ASSERT(!scratch2.is(reg));
__ pop(scratch2); // Get return address to place it below.
=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc Mon Aug 6 00:55:05 2012
+++ /branches/bleeding_edge/test/cctest/test-api.cc Mon Aug 6 07:25:19 2012
@@ -16973,9 +16973,9 @@
}
-THREADED_TEST(Regress137002a) {
- i::FLAG_allow_natives_syntax = true;
- v8::HandleScope scope;
+static void Helper137002(bool do_store,
+ bool polymorphic,
+ bool remove_accessor) {
LocalContext context;
Local<ObjectTemplate> templ = ObjectTemplate::New();
templ->SetAccessor(v8_str("foo"),
@@ -16985,13 +16985,46 @@
// Turn monomorphic on slow object with native accessor, then turn
// polymorphic, finally optimize to create negative lookup and fail.
- CompileRun("function f(x) { return x.foo; }"
+ CompileRun(do_store ?
+ "function f(x) { x.foo = void 0; }" :
+ "function f(x) { return x.foo; }");
+ CompileRun("obj.y = void 0;"
"%OptimizeObjectForAddingMultipleProperties(obj, 1);"
"obj.__proto__ = null;"
- "f(obj); f(obj); f({});"
- "%OptimizeFunctionOnNextCall(f);"
- "var result = f(obj);");
- CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
+ "f(obj); f(obj);");
+ if (polymorphic) {
+ CompileRun("f({});");
+ }
+ CompileRun("obj.y = void 0;"
+ "%OptimizeFunctionOnNextCall(f);");
+ if (remove_accessor) {
+ CompileRun("delete obj.foo;");
+ }
+ CompileRun("var result = f(obj);");
+ if (do_store) {
+ CompileRun("result = obj.y;");
+ }
+ if (remove_accessor) {
+ CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
+ } else {
+ CHECK_EQ(do_store ? 23 : 42,
+ context->Global()->Get(v8_str("result"))->Int32Value());
+ }
+}
+
+
+THREADED_TEST(Regress137002a) {
+ i::FLAG_allow_natives_syntax = true;
+ i::FLAG_compilation_cache = false;
+ v8::HandleScope scope;
+ Helper137002(false, false, false);
+ Helper137002(false, false, true);
+ Helper137002(false, true, false);
+ Helper137002(false, true, true);
+ Helper137002(true, false, false);
+ Helper137002(true, false, true);
+ Helper137002(true, true, false);
+ Helper137002(true, true, true);
}
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev