mirror of https://github.com/lukechilds/node.git
Ryan Dahl
14 years ago
103 changed files with 3959 additions and 2069 deletions
@ -0,0 +1,110 @@ |
|||
# Copyright 2011 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.
|
|||
|
|||
|
|||
# Variable default definitions. Override them by exporting them in your shell.
|
|||
CXX ?= "g++" # For distcc: export CXX="distcc g++" |
|||
LINK ?= "g++" |
|||
OUTDIR ?= out |
|||
TESTJOBS ?= -j16 |
|||
GYPFLAGS ?= -Dv8_can_use_vfp_instructions=true |
|||
|
|||
# Architectures and modes to be compiled.
|
|||
ARCHES = ia32 x64 arm |
|||
MODES = release debug |
|||
|
|||
# List of files that trigger Makefile regeneration:
|
|||
GYPFILES = build/all.gyp build/common.gypi build/v8-features.gypi \
|
|||
preparser/preparser.gyp samples/samples.gyp src/d8.gyp \
|
|||
test/cctest/cctest.gyp tools/gyp/v8.gyp |
|||
|
|||
# Generates all combinations of ARCHES and MODES, e.g. "ia32.release".
|
|||
BUILDS = $(foreach mode,$(MODES),$(addsuffix .$(mode),$(ARCHES))) |
|||
CHECKS = $(addsuffix .check,$(BUILDS)) |
|||
# Generates corresponding test targets, e.g. "ia32.release.check".
|
|||
|
|||
.PHONY: all release debug ia32 x64 arm $(BUILDS) |
|||
|
|||
# Target definitions. "all" is the default, you can specify any others on the
|
|||
# command line, e.g. "make ia32". Targets defined in $(BUILDS), e.g.
|
|||
# "ia32.debug", can also be specified.
|
|||
all: release debug |
|||
|
|||
release: $(addsuffix .release,$(ARCHES)) |
|||
|
|||
debug: $(addsuffix .debug,$(ARCHES)) |
|||
|
|||
ia32: $(addprefix ia32.,$(MODES)) |
|||
|
|||
x64: $(addprefix x64.,$(MODES)) |
|||
|
|||
arm: $(addprefix arm.,$(MODES)) |
|||
|
|||
.SECONDEXPANSION: |
|||
$(BUILDS): $(OUTDIR)/Makefile-$$(basename $$@) |
|||
@$(MAKE) -C "$(OUTDIR)" -f Makefile-$(basename $@) \
|
|||
CXX="$(CXX)" LINK="$(LINK)" \
|
|||
BUILDTYPE=$(shell echo $(subst .,,$(suffix $@)) | \
|
|||
python -c "print raw_input().capitalize()") \
|
|||
builddir="$(shell pwd)/$(OUTDIR)/$@" |
|||
|
|||
# Test targets.
|
|||
check: all |
|||
@tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR) |
|||
|
|||
$(addsuffix .check,$(MODES)): $$(basename $$@) |
|||
@tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR) --mode=$(basename $@) |
|||
|
|||
$(addsuffix .check,$(ARCHES)): $$(basename $$@) |
|||
@tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR) --arch=$(basename $@) |
|||
|
|||
$(CHECKS): $$(basename $$@) |
|||
@tools/test-wrapper-gypbuild.py $(TESTJOBS) --outdir=$(OUTDIR) --arch-and-mode=$(basename $@) |
|||
|
|||
# Clean targets. You can clean each architecture individually, or everything.
|
|||
$(addsuffix .clean,$(ARCHES)): |
|||
rm -f $(OUTDIR)/Makefile-$(basename $@) |
|||
rm -rf $(OUTDIR)/$(basename $@).release |
|||
rm -rf $(OUTDIR)/$(basename $@).debug |
|||
|
|||
clean: $(addsuffix .clean,$(ARCHES)) |
|||
|
|||
# GYP file generation targets.
|
|||
$(OUTDIR)/Makefile-ia32: $(GYPFILES) |
|||
build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \
|
|||
-Ibuild/common.gypi --depth=. -Dtarget_arch=ia32 -S-ia32 \
|
|||
$(GYPFLAGS) |
|||
|
|||
$(OUTDIR)/Makefile-x64: $(GYPFILES) |
|||
build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \
|
|||
-Ibuild/common.gypi --depth=. -Dtarget_arch=x64 -S-x64 \
|
|||
$(GYPFLAGS) |
|||
|
|||
$(OUTDIR)/Makefile-arm: $(GYPFILES) build/armu.gypi |
|||
build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \
|
|||
-Ibuild/common.gypi --depth=. -Ibuild/armu.gypi -S-arm \
|
|||
$(GYPFLAGS) |
@ -0,0 +1,41 @@ |
|||
# Copyright 2011 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. |
|||
|
|||
{ |
|||
'targets': [ |
|||
{ |
|||
'target_name': 'preparser', |
|||
'type': 'executable', |
|||
'dependencies': [ |
|||
'../tools/gyp/v8.gyp:preparser_lib', |
|||
], |
|||
'sources': [ |
|||
'preparser-process.cc', |
|||
], |
|||
}, |
|||
], |
|||
} |
@ -0,0 +1,536 @@ |
|||
// Copyright 2011 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.
|
|||
|
|||
#include "v8.h" |
|||
|
|||
#include "objects.h" |
|||
#include "elements.h" |
|||
|
|||
namespace v8 { |
|||
namespace internal { |
|||
|
|||
|
|||
ElementsAccessor** ElementsAccessor::elements_accessors_; |
|||
|
|||
|
|||
bool HasKey(FixedArray* array, Object* key) { |
|||
int len0 = array->length(); |
|||
for (int i = 0; i < len0; i++) { |
|||
Object* element = array->get(i); |
|||
if (element->IsSmi() && element == key) return true; |
|||
if (element->IsString() && |
|||
key->IsString() && String::cast(element)->Equals(String::cast(key))) { |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
|
|||
// Base class for element handler implementations. Contains the
|
|||
// the common logic for objects with different ElementsKinds.
|
|||
// Subclasses must specialize method for which the element
|
|||
// implementation differs from the base class implementation.
|
|||
//
|
|||
// This class is intended to be used in the following way:
|
|||
//
|
|||
// class SomeElementsAccessor :
|
|||
// public ElementsAccessorBase<SomeElementsAccessor,
|
|||
// BackingStoreClass> {
|
|||
// ...
|
|||
// }
|
|||
//
|
|||
// This is an example of the Curiously Recurring Template Pattern (see
|
|||
// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern). We use
|
|||
// CRTP to guarantee aggressive compile time optimizations (i.e. inlining and
|
|||
// specialization of SomeElementsAccessor methods).
|
|||
template <typename ElementsAccessorSubclass, typename BackingStoreClass> |
|||
class ElementsAccessorBase : public ElementsAccessor { |
|||
public: |
|||
ElementsAccessorBase() { } |
|||
virtual MaybeObject* GetWithReceiver(JSObject* obj, |
|||
Object* receiver, |
|||
uint32_t index) { |
|||
if (index < ElementsAccessorSubclass::GetLength(obj)) { |
|||
BackingStoreClass* backing_store = |
|||
ElementsAccessorSubclass::GetBackingStore(obj); |
|||
return backing_store->get(index); |
|||
} |
|||
return obj->GetHeap()->the_hole_value(); |
|||
} |
|||
|
|||
virtual MaybeObject* Delete(JSObject* obj, |
|||
uint32_t index, |
|||
JSReceiver::DeleteMode mode) = 0; |
|||
|
|||
virtual MaybeObject* AddJSArrayKeysToFixedArray(JSArray* other, |
|||
FixedArray* keys) { |
|||
int len0 = keys->length(); |
|||
#ifdef DEBUG |
|||
if (FLAG_enable_slow_asserts) { |
|||
for (int i = 0; i < len0; i++) { |
|||
ASSERT(keys->get(i)->IsString() || keys->get(i)->IsNumber()); |
|||
} |
|||
} |
|||
#endif |
|||
int len1 = ElementsAccessorSubclass::GetCapacity(other); |
|||
|
|||
// Optimize if 'other' is empty.
|
|||
// We cannot optimize if 'this' is empty, as other may have holes
|
|||
// or non keys.
|
|||
if (len1 == 0) return keys; |
|||
|
|||
// Compute how many elements are not in other.
|
|||
int extra = 0; |
|||
for (int y = 0; y < len1; y++) { |
|||
Object* value; |
|||
MaybeObject* maybe_value = |
|||
ElementsAccessorSubclass::GetElementAtCapacityIndex(other, y); |
|||
if (!maybe_value->ToObject(&value)) return maybe_value; |
|||
if (!value->IsTheHole() && !HasKey(keys, value)) extra++; |
|||
} |
|||
|
|||
if (extra == 0) return keys; |
|||
|
|||
// Allocate the result
|
|||
FixedArray* result; |
|||
MaybeObject* maybe_obj = |
|||
other->GetHeap()->AllocateFixedArray(len0 + extra); |
|||
if (!maybe_obj->To<FixedArray>(&result)) return maybe_obj; |
|||
|
|||
// Fill in the content
|
|||
{ |
|||
AssertNoAllocation no_gc; |
|||
WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); |
|||
for (int i = 0; i < len0; i++) { |
|||
Object* e = keys->get(i); |
|||
ASSERT(e->IsString() || e->IsNumber()); |
|||
result->set(i, e, mode); |
|||
} |
|||
} |
|||
// Fill in the extra keys.
|
|||
int index = 0; |
|||
for (int y = 0; y < len1; y++) { |
|||
MaybeObject* maybe_value = |
|||
ElementsAccessorSubclass::GetElementAtCapacityIndex(other, y); |
|||
Object* value; |
|||
if (!maybe_value->ToObject(&value)) return maybe_value; |
|||
if (!value->IsTheHole() && !HasKey(keys, value)) { |
|||
ASSERT(value->IsString() || value->IsNumber()); |
|||
result->set(len0 + index, value); |
|||
index++; |
|||
} |
|||
} |
|||
ASSERT(extra == index); |
|||
return result; |
|||
} |
|||
|
|||
static uint32_t GetCapacity(JSObject* obj) { |
|||
return ElementsAccessorSubclass::GetBackingStore(obj)->length(); |
|||
} |
|||
|
|||
static MaybeObject* GetElementAtCapacityIndex(JSObject* obj, int index) { |
|||
BackingStoreClass* backing_store = |
|||
ElementsAccessorSubclass::GetBackingStore(obj); |
|||
return backing_store->get(index); |
|||
} |
|||
|
|||
protected: |
|||
static BackingStoreClass* GetBackingStore(JSObject* obj) { |
|||
return BackingStoreClass::cast(obj->elements()); |
|||
} |
|||
|
|||
static uint32_t GetLength(JSObject* obj) { |
|||
return ElementsAccessorSubclass::GetBackingStore(obj)->length(); |
|||
} |
|||
|
|||
private: |
|||
DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase); |
|||
}; |
|||
|
|||
|
|||
class FastElementsAccessor |
|||
: public ElementsAccessorBase<FastElementsAccessor, FixedArray> { |
|||
public: |
|||
static MaybeObject* DeleteCommon(JSObject* obj, |
|||
uint32_t index) { |
|||
ASSERT(obj->HasFastElements() || obj->HasFastArgumentsElements()); |
|||
Heap* heap = obj->GetHeap(); |
|||
FixedArray* backing_store = FixedArray::cast(obj->elements()); |
|||
if (backing_store->map() == heap->non_strict_arguments_elements_map()) { |
|||
backing_store = FixedArray::cast(backing_store->get(1)); |
|||
} else { |
|||
Object* writable; |
|||
MaybeObject* maybe = obj->EnsureWritableFastElements(); |
|||
if (!maybe->ToObject(&writable)) return maybe; |
|||
backing_store = FixedArray::cast(writable); |
|||
} |
|||
uint32_t length = static_cast<uint32_t>( |
|||
obj->IsJSArray() |
|||
? Smi::cast(JSArray::cast(obj)->length())->value() |
|||
: backing_store->length()); |
|||
if (index < length) { |
|||
backing_store->set_the_hole(index); |
|||
// If an old space backing store is larger than a certain size and
|
|||
// has too few used values, normalize it.
|
|||
// To avoid doing the check on every delete we require at least
|
|||
// one adjacent hole to the value being deleted.
|
|||
Object* hole = heap->the_hole_value(); |
|||
const int kMinLengthForSparsenessCheck = 64; |
|||
if (backing_store->length() >= kMinLengthForSparsenessCheck && |
|||
!heap->InNewSpace(backing_store) && |
|||
((index > 0 && backing_store->get(index - 1) == hole) || |
|||
(index + 1 < length && backing_store->get(index + 1) == hole))) { |
|||
int num_used = 0; |
|||
for (int i = 0; i < backing_store->length(); ++i) { |
|||
if (backing_store->get(i) != hole) ++num_used; |
|||
// Bail out early if more than 1/4 is used.
|
|||
if (4 * num_used > backing_store->length()) break; |
|||
} |
|||
if (4 * num_used <= backing_store->length()) { |
|||
MaybeObject* result = obj->NormalizeElements(); |
|||
if (result->IsFailure()) return result; |
|||
} |
|||
} |
|||
} |
|||
return heap->true_value(); |
|||
} |
|||
|
|||
virtual MaybeObject* Delete(JSObject* obj, |
|||
uint32_t index, |
|||
JSReceiver::DeleteMode mode) { |
|||
return DeleteCommon(obj, index); |
|||
} |
|||
}; |
|||
|
|||
|
|||
class FastDoubleElementsAccessor |
|||
: public ElementsAccessorBase<FastDoubleElementsAccessor, |
|||
FixedDoubleArray> { |
|||
virtual MaybeObject* Delete(JSObject* obj, |
|||
uint32_t index, |
|||
JSReceiver::DeleteMode mode) { |
|||
int length = obj->IsJSArray() |
|||
? Smi::cast(JSArray::cast(obj)->length())->value() |
|||
: FixedDoubleArray::cast(obj->elements())->length(); |
|||
if (index < static_cast<uint32_t>(length)) { |
|||
FixedDoubleArray::cast(obj->elements())->set_the_hole(index); |
|||
} |
|||
return obj->GetHeap()->true_value(); |
|||
} |
|||
}; |
|||
|
|||
|
|||
// Super class for all external element arrays.
|
|||
template<typename ExternalElementsAccessorSubclass, |
|||
typename ExternalArray> |
|||
class ExternalElementsAccessor |
|||
: public ElementsAccessorBase<ExternalElementsAccessorSubclass, |
|||
ExternalArray> { |
|||
public: |
|||
virtual MaybeObject* GetWithReceiver(JSObject* obj, |
|||
Object* receiver, |
|||
uint32_t index) { |
|||
if (index < ExternalElementsAccessorSubclass::GetLength(obj)) { |
|||
ExternalArray* backing_store = |
|||
ExternalElementsAccessorSubclass::GetBackingStore(obj); |
|||
return backing_store->get(index); |
|||
} else { |
|||
return obj->GetHeap()->undefined_value(); |
|||
} |
|||
} |
|||
|
|||
virtual MaybeObject* Delete(JSObject* obj, |
|||
uint32_t index, |
|||
JSReceiver::DeleteMode mode) { |
|||
// External arrays always ignore deletes.
|
|||
return obj->GetHeap()->true_value(); |
|||
} |
|||
}; |
|||
|
|||
|
|||
class ExternalByteElementsAccessor |
|||
: public ExternalElementsAccessor<ExternalByteElementsAccessor, |
|||
ExternalByteArray> { |
|||
}; |
|||
|
|||
|
|||
class ExternalUnsignedByteElementsAccessor |
|||
: public ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor, |
|||
ExternalUnsignedByteArray> { |
|||
}; |
|||
|
|||
|
|||
class ExternalShortElementsAccessor |
|||
: public ExternalElementsAccessor<ExternalShortElementsAccessor, |
|||
ExternalShortArray> { |
|||
}; |
|||
|
|||
|
|||
class ExternalUnsignedShortElementsAccessor |
|||
: public ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor, |
|||
ExternalUnsignedShortArray> { |
|||
}; |
|||
|
|||
|
|||
class ExternalIntElementsAccessor |
|||
: public ExternalElementsAccessor<ExternalIntElementsAccessor, |
|||
ExternalIntArray> { |
|||
}; |
|||
|
|||
|
|||
class ExternalUnsignedIntElementsAccessor |
|||
: public ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor, |
|||
ExternalUnsignedIntArray> { |
|||
}; |
|||
|
|||
|
|||
class ExternalFloatElementsAccessor |
|||
: public ExternalElementsAccessor<ExternalFloatElementsAccessor, |
|||
ExternalFloatArray> { |
|||
}; |
|||
|
|||
|
|||
class ExternalDoubleElementsAccessor |
|||
: public ExternalElementsAccessor<ExternalDoubleElementsAccessor, |
|||
ExternalDoubleArray> { |
|||
}; |
|||
|
|||
|
|||
class PixelElementsAccessor |
|||
: public ExternalElementsAccessor<PixelElementsAccessor, |
|||
ExternalPixelArray> { |
|||
}; |
|||
|
|||
|
|||
class DictionaryElementsAccessor |
|||
: public ElementsAccessorBase<DictionaryElementsAccessor, |
|||
NumberDictionary> { |
|||
public: |
|||
static MaybeObject* GetNumberDictionaryElement( |
|||
JSObject* obj, |
|||
Object* receiver, |
|||
NumberDictionary* backing_store, |
|||
uint32_t index) { |
|||
int entry = backing_store->FindEntry(index); |
|||
if (entry != NumberDictionary::kNotFound) { |
|||
Object* element = backing_store->ValueAt(entry); |
|||
PropertyDetails details = backing_store->DetailsAt(entry); |
|||
if (details.type() == CALLBACKS) { |
|||
return obj->GetElementWithCallback(receiver, |
|||
element, |
|||
index, |
|||
obj); |
|||
} else { |
|||
return element; |
|||
} |
|||
} |
|||
return obj->GetHeap()->the_hole_value(); |
|||
} |
|||
|
|||
|
|||
static MaybeObject* DeleteCommon(JSObject* obj, |
|||
uint32_t index, |
|||
JSReceiver::DeleteMode mode) { |
|||
Isolate* isolate = obj->GetIsolate(); |
|||
Heap* heap = isolate->heap(); |
|||
FixedArray* backing_store = FixedArray::cast(obj->elements()); |
|||
bool is_arguments = |
|||
(obj->GetElementsKind() == JSObject::NON_STRICT_ARGUMENTS_ELEMENTS); |
|||
if (is_arguments) { |
|||
backing_store = FixedArray::cast(backing_store->get(1)); |
|||
} |
|||
NumberDictionary* dictionary = NumberDictionary::cast(backing_store); |
|||
int entry = dictionary->FindEntry(index); |
|||
if (entry != NumberDictionary::kNotFound) { |
|||
Object* result = dictionary->DeleteProperty(entry, mode); |
|||
if (result == heap->true_value()) { |
|||
MaybeObject* maybe_elements = dictionary->Shrink(index); |
|||
FixedArray* new_elements = NULL; |
|||
if (!maybe_elements->To(&new_elements)) { |
|||
return maybe_elements; |
|||
} |
|||
if (is_arguments) { |
|||
FixedArray::cast(obj->elements())->set(1, new_elements); |
|||
} else { |
|||
obj->set_elements(new_elements); |
|||
} |
|||
} |
|||
if (mode == JSObject::STRICT_DELETION && |
|||
result == heap->false_value()) { |
|||
// In strict mode, attempting to delete a non-configurable property
|
|||
// throws an exception.
|
|||
HandleScope scope(isolate); |
|||
Handle<Object> holder(obj); |
|||
Handle<Object> name = isolate->factory()->NewNumberFromUint(index); |
|||
Handle<Object> args[2] = { name, holder }; |
|||
Handle<Object> error = |
|||
isolate->factory()->NewTypeError("strict_delete_property", |
|||
HandleVector(args, 2)); |
|||
return isolate->Throw(*error); |
|||
} |
|||
} |
|||
return heap->true_value(); |
|||
} |
|||
|
|||
virtual MaybeObject* Delete(JSObject* obj, |
|||
uint32_t index, |
|||
JSReceiver::DeleteMode mode) { |
|||
return DeleteCommon(obj, index, mode); |
|||
} |
|||
|
|||
virtual MaybeObject* GetWithReceiver(JSObject* obj, |
|||
Object* receiver, |
|||
uint32_t index) { |
|||
return GetNumberDictionaryElement(obj, |
|||
receiver, |
|||
obj->element_dictionary(), |
|||
index); |
|||
} |
|||
|
|||
static uint32_t GetCapacity(JSObject* obj) { |
|||
return obj->element_dictionary()->Capacity(); |
|||
} |
|||
|
|||
static MaybeObject* GetElementAtCapacityIndex(JSObject* obj, int index) { |
|||
NumberDictionary* dict = obj->element_dictionary(); |
|||
if (dict->IsKey(dict->KeyAt(index))) { |
|||
return dict->ValueAt(index); |
|||
} else { |
|||
return obj->GetHeap()->the_hole_value(); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
|
|||
class NonStrictArgumentsElementsAccessor |
|||
: public ElementsAccessorBase<NonStrictArgumentsElementsAccessor, |
|||
FixedArray> { |
|||
public: |
|||
virtual MaybeObject* GetWithReceiver(JSObject* obj, |
|||
Object* receiver, |
|||
uint32_t index) { |
|||
FixedArray* parameter_map = GetBackingStore(obj); |
|||
uint32_t length = parameter_map->length(); |
|||
Object* probe = |
|||
(index < length - 2) ? parameter_map->get(index + 2) : NULL; |
|||
if (probe != NULL && !probe->IsTheHole()) { |
|||
Context* context = Context::cast(parameter_map->get(0)); |
|||
int context_index = Smi::cast(probe)->value(); |
|||
ASSERT(!context->get(context_index)->IsTheHole()); |
|||
return context->get(context_index); |
|||
} else { |
|||
// Object is not mapped, defer to the arguments.
|
|||
FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
|||
if (arguments->IsDictionary()) { |
|||
return DictionaryElementsAccessor::GetNumberDictionaryElement( |
|||
obj, |
|||
receiver, |
|||
NumberDictionary::cast(arguments), |
|||
index); |
|||
} else if (index < static_cast<uint32_t>(arguments->length())) { |
|||
return arguments->get(index); |
|||
} |
|||
} |
|||
return obj->GetHeap()->the_hole_value(); |
|||
} |
|||
|
|||
virtual MaybeObject* Delete(JSObject* obj, |
|||
uint32_t index, |
|||
JSReceiver::DeleteMode mode) { |
|||
FixedArray* parameter_map = FixedArray::cast(obj->elements()); |
|||
uint32_t length = parameter_map->length(); |
|||
Object* probe = |
|||
index < (length - 2) ? parameter_map->get(index + 2) : NULL; |
|||
if (probe != NULL && !probe->IsTheHole()) { |
|||
// TODO(kmillikin): We could check if this was the last aliased
|
|||
// parameter, and revert to normal elements in that case. That
|
|||
// would enable GC of the context.
|
|||
parameter_map->set_the_hole(index + 2); |
|||
} else { |
|||
FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
|||
if (arguments->IsDictionary()) { |
|||
return DictionaryElementsAccessor::DeleteCommon(obj, index, mode); |
|||
} else { |
|||
return FastElementsAccessor::DeleteCommon(obj, index); |
|||
} |
|||
} |
|||
return obj->GetHeap()->true_value(); |
|||
} |
|||
|
|||
static uint32_t GetCapacity(JSObject* obj) { |
|||
// TODO(danno): Return max of parameter map length or backing store
|
|||
// capacity.
|
|||
return 0; |
|||
} |
|||
|
|||
static MaybeObject* GetElementAtCapacityIndex(JSObject* obj, int index) { |
|||
// TODO(danno): Return either value from parameter map of backing
|
|||
// store value at index.
|
|||
return obj->GetHeap()->the_hole_value(); |
|||
} |
|||
}; |
|||
|
|||
|
|||
void ElementsAccessor::InitializeOncePerProcess() { |
|||
static struct ConcreteElementsAccessors { |
|||
FastElementsAccessor fast_elements_handler; |
|||
FastDoubleElementsAccessor fast_double_elements_handler; |
|||
DictionaryElementsAccessor dictionary_elements_handler; |
|||
NonStrictArgumentsElementsAccessor non_strict_arguments_elements_handler; |
|||
ExternalByteElementsAccessor byte_elements_handler; |
|||
ExternalUnsignedByteElementsAccessor unsigned_byte_elements_handler; |
|||
ExternalShortElementsAccessor short_elements_handler; |
|||
ExternalUnsignedShortElementsAccessor unsigned_short_elements_handler; |
|||
ExternalIntElementsAccessor int_elements_handler; |
|||
ExternalUnsignedIntElementsAccessor unsigned_int_elements_handler; |
|||
ExternalFloatElementsAccessor float_elements_handler; |
|||
ExternalDoubleElementsAccessor double_elements_handler; |
|||
PixelElementsAccessor pixel_elements_handler; |
|||
} element_accessors; |
|||
|
|||
static ElementsAccessor* accessor_array[] = { |
|||
&element_accessors.fast_elements_handler, |
|||
&element_accessors.fast_double_elements_handler, |
|||
&element_accessors.dictionary_elements_handler, |
|||
&element_accessors.non_strict_arguments_elements_handler, |
|||
&element_accessors.byte_elements_handler, |
|||
&element_accessors.unsigned_byte_elements_handler, |
|||
&element_accessors.short_elements_handler, |
|||
&element_accessors.unsigned_short_elements_handler, |
|||
&element_accessors.int_elements_handler, |
|||
&element_accessors.unsigned_int_elements_handler, |
|||
&element_accessors.float_elements_handler, |
|||
&element_accessors.double_elements_handler, |
|||
&element_accessors.pixel_elements_handler |
|||
}; |
|||
|
|||
elements_accessors_ = accessor_array; |
|||
} |
|||
|
|||
|
|||
} } // namespace v8::internal
|
@ -0,0 +1,69 @@ |
|||
// Copyright 2011 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.
|
|||
|
|||
#ifndef V8_ELEMENTS_H_ |
|||
#define V8_ELEMENTS_H_ |
|||
|
|||
#include "objects.h" |
|||
|
|||
namespace v8 { |
|||
namespace internal { |
|||
|
|||
// Abstract base class for handles that can operate on objects with differing
|
|||
// ElementsKinds.
|
|||
class ElementsAccessor { |
|||
public: |
|||
ElementsAccessor() { } |
|||
virtual ~ElementsAccessor() { } |
|||
virtual MaybeObject* GetWithReceiver(JSObject* obj, |
|||
Object* receiver, |
|||
uint32_t index) = 0; |
|||
|
|||
virtual MaybeObject* Delete(JSObject* obj, |
|||
uint32_t index, |
|||
JSReceiver::DeleteMode mode) = 0; |
|||
|
|||
virtual MaybeObject* AddJSArrayKeysToFixedArray(JSArray* other, |
|||
FixedArray* keys) = 0; |
|||
|
|||
// Returns a shared ElementsAccessor for the specified ElementsKind.
|
|||
static ElementsAccessor* ForKind(JSObject::ElementsKind elements_kind) { |
|||
ASSERT(elements_kind < JSObject::kElementsKindCount); |
|||
return elements_accessors_[elements_kind]; |
|||
} |
|||
|
|||
static void InitializeOncePerProcess(); |
|||
|
|||
private: |
|||
static ElementsAccessor** elements_accessors_; |
|||
|
|||
DISALLOW_COPY_AND_ASSIGN(ElementsAccessor); |
|||
}; |
|||
|
|||
} } // namespace v8::internal
|
|||
|
|||
#endif // V8_ELEMENTS_H_
|
File diff suppressed because it is too large
@ -0,0 +1,95 @@ |
|||
// Copyright 2011 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.
|
|||
|
|||
|
|||
// This file relies on the fact that the following declaration has been made
|
|||
// in runtime.js:
|
|||
// const $Object = global.Object;
|
|||
const $WeakMap = global.WeakMap; |
|||
|
|||
// -------------------------------------------------------------------
|
|||
|
|||
// Set the WeakMap function and constructor.
|
|||
%SetCode($WeakMap, function(x) { |
|||
if (%_IsConstructCall()) { |
|||
%WeakMapInitialize(this); |
|||
} else { |
|||
return new $WeakMap(); |
|||
} |
|||
}); |
|||
|
|||
|
|||
function WeakMapGet(key) { |
|||
if (!IS_SPEC_OBJECT(key)) { |
|||
throw %MakeTypeError('invalid_weakmap_key', [this, key]); |
|||
} |
|||
return %WeakMapGet(this, key); |
|||
} |
|||
|
|||
|
|||
function WeakMapSet(key, value) { |
|||
if (!IS_SPEC_OBJECT(key)) { |
|||
throw %MakeTypeError('invalid_weakmap_key', [this, key]); |
|||
} |
|||
return %WeakMapSet(this, key, value); |
|||
} |
|||
|
|||
|
|||
function WeakMapHas(key) { |
|||
if (!IS_SPEC_OBJECT(key)) { |
|||
throw %MakeTypeError('invalid_weakmap_key', [this, key]); |
|||
} |
|||
return !IS_UNDEFINED(%WeakMapGet(this, key)); |
|||
} |
|||
|
|||
|
|||
function WeakMapDelete(key) { |
|||
if (!IS_SPEC_OBJECT(key)) { |
|||
throw %MakeTypeError('invalid_weakmap_key', [this, key]); |
|||
} |
|||
if (!IS_UNDEFINED(%WeakMapGet(this, key))) { |
|||
%WeakMapSet(this, key, void 0); |
|||
return true; |
|||
} else { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
// -------------------------------------------------------------------
|
|||
|
|||
function SetupWeakMap() { |
|||
// Setup the non-enumerable functions on the WeakMap prototype object.
|
|||
InstallFunctionsOnHiddenPrototype($WeakMap.prototype, DONT_ENUM, $Array( |
|||
"get", WeakMapGet, |
|||
"set", WeakMapSet, |
|||
"has", WeakMapHas, |
|||
"delete", WeakMapDelete |
|||
)); |
|||
} |
|||
|
|||
|
|||
SetupWeakMap(); |
@ -0,0 +1,149 @@ |
|||
// Copyright 2011 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.
|
|||
|
|||
#include "v8.h" |
|||
|
|||
#include "global-handles.h" |
|||
#include "snapshot.h" |
|||
#include "cctest.h" |
|||
|
|||
using namespace v8::internal; |
|||
|
|||
|
|||
static Handle<JSWeakMap> AllocateJSWeakMap() { |
|||
Handle<Map> map = FACTORY->NewMap(JS_WEAK_MAP_TYPE, JSWeakMap::kSize); |
|||
Handle<JSObject> weakmap_obj = FACTORY->NewJSObjectFromMap(map); |
|||
Handle<JSWeakMap> weakmap(JSWeakMap::cast(*weakmap_obj)); |
|||
// Do not use handles for the hash table, it would make entries strong.
|
|||
Object* table_obj = ObjectHashTable::Allocate(1)->ToObjectChecked(); |
|||
ObjectHashTable* table = ObjectHashTable::cast(table_obj); |
|||
weakmap->set_table(table); |
|||
weakmap->set_next(Smi::FromInt(0)); |
|||
return weakmap; |
|||
} |
|||
|
|||
static void PutIntoWeakMap(Handle<JSWeakMap> weakmap, |
|||
Handle<JSObject> key, |
|||
int value) { |
|||
Handle<ObjectHashTable> table = PutIntoObjectHashTable( |
|||
Handle<ObjectHashTable>(weakmap->table()), |
|||
Handle<JSObject>(JSObject::cast(*key)), |
|||
Handle<Smi>(Smi::FromInt(value))); |
|||
weakmap->set_table(*table); |
|||
} |
|||
|
|||
static int NumberOfWeakCalls = 0; |
|||
static void WeakPointerCallback(v8::Persistent<v8::Value> handle, void* id) { |
|||
ASSERT(id == reinterpret_cast<void*>(1234)); |
|||
NumberOfWeakCalls++; |
|||
handle.Dispose(); |
|||
} |
|||
|
|||
|
|||
TEST(Weakness) { |
|||
LocalContext context; |
|||
v8::HandleScope scope; |
|||
Handle<JSWeakMap> weakmap = AllocateJSWeakMap(); |
|||
GlobalHandles* global_handles = Isolate::Current()->global_handles(); |
|||
|
|||
// Keep global reference to the key.
|
|||
Handle<Object> key; |
|||
{ |
|||
v8::HandleScope scope; |
|||
Handle<Map> map = FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); |
|||
Handle<JSObject> object = FACTORY->NewJSObjectFromMap(map); |
|||
key = global_handles->Create(*object); |
|||
} |
|||
CHECK(!global_handles->IsWeak(key.location())); |
|||
|
|||
// Put entry into weak map.
|
|||
{ |
|||
v8::HandleScope scope; |
|||
PutIntoWeakMap(weakmap, Handle<JSObject>(JSObject::cast(*key)), 23); |
|||
} |
|||
CHECK_EQ(1, weakmap->table()->NumberOfElements()); |
|||
|
|||
// Force a full GC.
|
|||
HEAP->CollectAllGarbage(false); |
|||
CHECK_EQ(0, NumberOfWeakCalls); |
|||
CHECK_EQ(1, weakmap->table()->NumberOfElements()); |
|||
CHECK_EQ(0, weakmap->table()->NumberOfDeletedElements()); |
|||
|
|||
// Make the global reference to the key weak.
|
|||
{ |
|||
v8::HandleScope scope; |
|||
global_handles->MakeWeak(key.location(), |
|||
reinterpret_cast<void*>(1234), |
|||
&WeakPointerCallback); |
|||
} |
|||
CHECK(global_handles->IsWeak(key.location())); |
|||
|
|||
// Force a full GC.
|
|||
// Perform two consecutive GCs because the first one will only clear
|
|||
// weak references whereas the second one will also clear weak maps.
|
|||
HEAP->CollectAllGarbage(false); |
|||
CHECK_EQ(1, NumberOfWeakCalls); |
|||
CHECK_EQ(1, weakmap->table()->NumberOfElements()); |
|||
CHECK_EQ(0, weakmap->table()->NumberOfDeletedElements()); |
|||
HEAP->CollectAllGarbage(false); |
|||
CHECK_EQ(1, NumberOfWeakCalls); |
|||
CHECK_EQ(0, weakmap->table()->NumberOfElements()); |
|||
CHECK_EQ(1, weakmap->table()->NumberOfDeletedElements()); |
|||
} |
|||
|
|||
|
|||
TEST(Shrinking) { |
|||
LocalContext context; |
|||
v8::HandleScope scope; |
|||
Handle<JSWeakMap> weakmap = AllocateJSWeakMap(); |
|||
|
|||
// Check initial capacity.
|
|||
CHECK_EQ(32, weakmap->table()->Capacity()); |
|||
|
|||
// Fill up weak map to trigger capacity change.
|
|||
{ |
|||
v8::HandleScope scope; |
|||
Handle<Map> map = FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); |
|||
for (int i = 0; i < 32; i++) { |
|||
Handle<JSObject> object = FACTORY->NewJSObjectFromMap(map); |
|||
PutIntoWeakMap(weakmap, object, i); |
|||
} |
|||
} |
|||
|
|||
// Check increased capacity.
|
|||
CHECK_EQ(128, weakmap->table()->Capacity()); |
|||
|
|||
// Force a full GC.
|
|||
CHECK_EQ(32, weakmap->table()->NumberOfElements()); |
|||
CHECK_EQ(0, weakmap->table()->NumberOfDeletedElements()); |
|||
HEAP->CollectAllGarbage(false); |
|||
CHECK_EQ(0, weakmap->table()->NumberOfElements()); |
|||
CHECK_EQ(32, weakmap->table()->NumberOfDeletedElements()); |
|||
|
|||
// Check shrunk capacity.
|
|||
CHECK_EQ(32, weakmap->table()->Capacity()); |
|||
} |
@ -0,0 +1,145 @@ |
|||
// Copyright 2011 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.
|
|||
|
|||
// Flags: --harmony-weakmaps --expose-gc
|
|||
|
|||
|
|||
// Test valid getter and setter calls
|
|||
var m = new WeakMap; |
|||
assertDoesNotThrow(function () { m.get(new Object) }); |
|||
assertDoesNotThrow(function () { m.set(new Object) }); |
|||
assertDoesNotThrow(function () { m.has(new Object) }); |
|||
assertDoesNotThrow(function () { m.delete(new Object) }); |
|||
|
|||
|
|||
// Test invalid getter and setter calls
|
|||
var m = new WeakMap; |
|||
assertThrows(function () { m.get(undefined) }, TypeError); |
|||
assertThrows(function () { m.set(undefined, 0) }, TypeError); |
|||
assertThrows(function () { m.get(0) }, TypeError); |
|||
assertThrows(function () { m.set(0, 0) }, TypeError); |
|||
assertThrows(function () { m.get('a-key') }, TypeError); |
|||
assertThrows(function () { m.set('a-key', 0) }, TypeError); |
|||
|
|||
|
|||
// Test expected mapping behavior
|
|||
var m = new WeakMap; |
|||
function TestMapping(map, key, value) { |
|||
map.set(key, value); |
|||
assertSame(value, map.get(key)); |
|||
} |
|||
TestMapping(m, new Object, 23); |
|||
TestMapping(m, new Object, 'the-value'); |
|||
TestMapping(m, new Object, new Object); |
|||
|
|||
|
|||
// Test expected querying behavior
|
|||
var m = new WeakMap; |
|||
var key = new Object; |
|||
TestMapping(m, key, 'to-be-present'); |
|||
assertTrue(m.has(key)); |
|||
assertFalse(m.has(new Object)); |
|||
TestMapping(m, key, undefined); |
|||
assertFalse(m.has(key)); |
|||
assertFalse(m.has(new Object)); |
|||
|
|||
|
|||
// Test expected deletion behavior
|
|||
var m = new WeakMap; |
|||
var key = new Object; |
|||
TestMapping(m, key, 'to-be-deleted'); |
|||
assertTrue(m.delete(key)); |
|||
assertFalse(m.delete(key)); |
|||
assertFalse(m.delete(new Object)); |
|||
assertSame(m.get(key), undefined); |
|||
|
|||
|
|||
// Test GC of map with entry
|
|||
var m = new WeakMap; |
|||
var key = new Object; |
|||
m.set(key, 'not-collected'); |
|||
gc(); |
|||
assertSame('not-collected', m.get(key)); |
|||
|
|||
|
|||
// Test GC of map with chained entries
|
|||
var m = new WeakMap; |
|||
var head = new Object; |
|||
for (key = head, i = 0; i < 10; i++, key = m.get(key)) { |
|||
m.set(key, new Object); |
|||
} |
|||
gc(); |
|||
var count = 0; |
|||
for (key = head; key != undefined; key = m.get(key)) { |
|||
count++; |
|||
} |
|||
assertEquals(11, count); |
|||
|
|||
|
|||
// Test property attribute [[Enumerable]]
|
|||
var m = new WeakMap; |
|||
function props(x) { |
|||
var array = []; |
|||
for (var p in x) array.push(p); |
|||
return array.sort(); |
|||
} |
|||
assertArrayEquals([], props(WeakMap)); |
|||
assertArrayEquals([], props(WeakMap.prototype)); |
|||
assertArrayEquals([], props(m)); |
|||
|
|||
|
|||
// Test arbitrary properties on weak maps
|
|||
var m = new WeakMap; |
|||
function TestProperty(map, property, value) { |
|||
map[property] = value; |
|||
assertEquals(value, map[property]); |
|||
} |
|||
for (i = 0; i < 20; i++) { |
|||
TestProperty(m, i, 'val' + i); |
|||
TestProperty(m, 'foo' + i, 'bar' + i); |
|||
} |
|||
TestMapping(m, new Object, 'foobar'); |
|||
|
|||
|
|||
// Test direct constructor call
|
|||
var m = WeakMap(); |
|||
assertTrue(m instanceof WeakMap); |
|||
|
|||
|
|||
// Test some common JavaScript idioms
|
|||
var m = new WeakMap; |
|||
assertTrue(m instanceof WeakMap); |
|||
assertTrue(WeakMap.prototype.set instanceof Function) |
|||
assertTrue(WeakMap.prototype.get instanceof Function) |
|||
assertTrue(WeakMap.prototype.has instanceof Function) |
|||
assertTrue(WeakMap.prototype.delete instanceof Function) |
|||
|
|||
|
|||
// Stress Test
|
|||
// There is a proposed stress-test available at the es-discuss mailing list
|
|||
// which cannot be reasonably automated. Check it out by hand if you like:
|
|||
// https://mail.mozilla.org/pipermail/es-discuss/2011-May/014096.html
|
@ -0,0 +1,32 @@ |
|||
// Copyright 2011 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.
|
|||
|
|||
// See: http://code.google.com/p/v8/issues/detail?id=1546
|
|||
|
|||
// Should't throw. Scanner incorrectly truncated to char before comparing
|
|||
// with "*", so it ended the comment early.
|
|||
eval("/*\u822a/ */"); |
@ -0,0 +1,57 @@ |
|||
// Copyright 2011 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.
|
|||
|
|||
// Flags: --allow-natives-syntax
|
|||
|
|||
// Regression test for a bug in recompilation of anonymous functions inside
|
|||
// catch. We would incorrectly hoist them outside the catch in some cases.
|
|||
function f() { |
|||
try { |
|||
throw 0; |
|||
} catch (e) { |
|||
try { |
|||
var x = { a: 'hest' }; |
|||
x.m = function (e) { return x.a; }; |
|||
} catch (e) { |
|||
} |
|||
} |
|||
return x; |
|||
} |
|||
|
|||
var o = f(); |
|||
assertEquals('hest', o.m()); |
|||
assertEquals('hest', o.m()); |
|||
assertEquals('hest', o.m()); |
|||
%OptimizeFunctionOnNextCall(o.m); |
|||
assertEquals('hest', o.m()); |
|||
|
|||
// Fixing the bug above introduced (revealed?) an inconsistency in named
|
|||
// getters and setters. The property name was also treated as a function
|
|||
// name.
|
|||
var global = 'horse'; |
|||
var p = { get global() { return global; }}; |
|||
assertEquals('horse', p.global); |
@ -0,0 +1,64 @@ |
|||
// Copyright 2011 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.
|
|||
|
|||
// Flags: --expose-debug-as debug
|
|||
|
|||
// Test debug evaluation for functions without local context, but with
|
|||
// nested catch contexts.
|
|||
|
|||
function f() { |
|||
var i = 1; // Line 1.
|
|||
{ // Line 2.
|
|||
try { // Line 3.
|
|||
throw 'stuff'; // Line 4.
|
|||
} catch (e) { // Line 5.
|
|||
x = 2; // Line 6.
|
|||
} |
|||
} |
|||
}; |
|||
|
|||
// Get the Debug object exposed from the debug context global object.
|
|||
Debug = debug.Debug |
|||
// Set breakpoint on line 6.
|
|||
var bp = Debug.setBreakPoint(f, 6); |
|||
|
|||
function listener(event, exec_state, event_data, data) { |
|||
if (event == Debug.DebugEvent.Break) { |
|||
result = exec_state.frame().evaluate("i").value(); |
|||
} |
|||
}; |
|||
|
|||
// Add the debug event listener.
|
|||
Debug.setListener(listener); |
|||
result = -1; |
|||
f(); |
|||
assertEquals(1, result); |
|||
|
|||
// Clear breakpoint.
|
|||
Debug.clearBreakPoint(bp); |
|||
// Get rid of the debug event listener.
|
|||
Debug.setListener(null); |
@ -0,0 +1,112 @@ |
|||
// Copyright 2011 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.
|
|||
|
|||
// Getting property names of an object with a prototype chain that
|
|||
// triggers dictionary elements in GetLocalPropertyNames() shouldn't
|
|||
// crash the runtime
|
|||
|
|||
// Flags: --allow-natives-syntax
|
|||
|
|||
function Object1() { |
|||
this.foo = 1; |
|||
} |
|||
|
|||
function Object2() { |
|||
this.fuz = 2; |
|||
this.objects = new Object(); |
|||
this.fuz1 = 2; |
|||
this.fuz2 = 2; |
|||
this.fuz3 = 2; |
|||
this.fuz4 = 2; |
|||
this.fuz5 = 2; |
|||
this.fuz6 = 2; |
|||
this.fuz7 = 2; |
|||
this.fuz8 = 2; |
|||
this.fuz9 = 2; |
|||
this.fuz10 = 2; |
|||
this.fuz11 = 2; |
|||
this.fuz12 = 2; |
|||
this.fuz13 = 2; |
|||
this.fuz14 = 2; |
|||
this.fuz15 = 2; |
|||
this.fuz16 = 2; |
|||
this.fuz17 = 2; |
|||
// Force dictionary-based properties
|
|||
for (x=1;x<1000;x++) { |
|||
this["sdf" + x] = 2; |
|||
} |
|||
} |
|||
|
|||
function Object3() { |
|||
this.boo = 3; |
|||
} |
|||
|
|||
function Object4() { |
|||
this.baz = 4; |
|||
} |
|||
|
|||
obj1 = new Object1(); |
|||
obj2 = new Object2(); |
|||
obj3 = new Object3(); |
|||
obj4 = new Object4(); |
|||
|
|||
%SetHiddenPrototype(obj4, obj3); |
|||
%SetHiddenPrototype(obj3, obj2); |
|||
%SetHiddenPrototype(obj2, obj1); |
|||
|
|||
function contains(a, obj) { |
|||
for(var i = 0; i < a.length; i++) { |
|||
if(a[i] === obj){ |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
names = %GetLocalPropertyNames(obj4); |
|||
assertEquals(1021, names.length); |
|||
assertTrue(contains(names, "baz")); |
|||
assertTrue(contains(names, "boo")); |
|||
assertTrue(contains(names, "foo")); |
|||
assertTrue(contains(names, "fuz")); |
|||
assertTrue(contains(names, "fuz1")); |
|||
assertTrue(contains(names, "fuz2")); |
|||
assertTrue(contains(names, "fuz3")); |
|||
assertTrue(contains(names, "fuz4")); |
|||
assertTrue(contains(names, "fuz5")); |
|||
assertTrue(contains(names, "fuz6")); |
|||
assertTrue(contains(names, "fuz7")); |
|||
assertTrue(contains(names, "fuz8")); |
|||
assertTrue(contains(names, "fuz9")); |
|||
assertTrue(contains(names, "fuz10")); |
|||
assertTrue(contains(names, "fuz11")); |
|||
assertTrue(contains(names, "fuz12")); |
|||
assertTrue(contains(names, "fuz13")); |
|||
assertTrue(contains(names, "fuz14")); |
|||
assertTrue(contains(names, "fuz15")); |
|||
assertTrue(contains(names, "fuz16")); |
|||
assertTrue(contains(names, "fuz17")); |
|||
assertFalse(names[1020] == undefined); |
@ -0,0 +1,35 @@ |
|||
// Copyright 2011 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.
|
|||
|
|||
// Unterminated non-ASCII string literals in JSON code were not
|
|||
// detected correctly.
|
|||
|
|||
// Shouldn't crash (due to stack overflow).
|
|||
// Should throw due to invalid syntax.
|
|||
assertThrows(function() { |
|||
JSON.parse('"\x80unterminated'); |
|||
}); |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue