Version 3.19.10
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@14980 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index 25d11b1..bdfc73f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2013-06-06: Version 3.19.10
+
+ Performance and stability improvements on all platforms.
+
+
2013-06-05: Version 3.19.9
Implemented Load IC support for loading properties from primitive
diff --git a/include/v8.h b/include/v8.h
index 28a63f0..7a38c1e 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -1524,11 +1524,19 @@
V8_DEPRECATED(V8_INLINE(bool MayContainNonAscii()) const) { return true; }
/**
- * Returns whether this string contains only one byte data.
+ * Returns whether this string is known to contain only one byte data.
+ * Does not read the string.
+ * False negatives are possible.
*/
bool IsOneByte() const;
/**
+ * Returns whether this string contain only one byte data.
+ * Will read the entire string in some cases.
+ */
+ bool ContainsOnlyOneByte() const;
+
+ /**
* Write the contents of the string to an external buffer.
* If no arguments are given, expects the buffer to be large
* enough to hold the entire string and NULL terminator. Copies
@@ -2811,7 +2819,10 @@
template<typename T>
class ReturnValue {
public:
- V8_INLINE(explicit ReturnValue(internal::Object** slot));
+ template <class S> V8_INLINE(ReturnValue(const ReturnValue<S>& that))
+ : value_(that.value_) {
+ TYPE_CHECK(T, S);
+ }
// Handle setters
template <typename S> V8_INLINE(void Set(const Persistent<S>& handle));
template <typename S> V8_INLINE(void Set(const Handle<S> handle));
@@ -2825,7 +2836,12 @@
V8_INLINE(void SetUndefined());
// Convenience getter for Isolate
V8_INLINE(Isolate* GetIsolate());
+
private:
+ template<class F> friend class ReturnValue;
+ template<class F> friend class FunctionCallbackInfo;
+ template<class F> friend class PropertyCallbackInfo;
+ V8_INLINE(explicit ReturnValue(internal::Object** slot));
internal::Object** value_;
};
diff --git a/src/api.cc b/src/api.cc
index b2dc2e1..4cdd77e 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -4304,6 +4304,85 @@
}
+class ContainsOnlyOneByteHelper {
+ public:
+ ContainsOnlyOneByteHelper() : is_one_byte_(true) {}
+ bool Check(i::String* string) {
+ i::ConsString* cons_string = i::String::VisitFlat(this, string, 0);
+ if (cons_string == NULL) return is_one_byte_;
+ return CheckCons(cons_string);
+ }
+ void VisitOneByteString(const uint8_t* chars, int length) {
+ // Nothing to do.
+ }
+ // TODO(dcarney): do word aligned read.
+ void VisitTwoByteString(const uint16_t* chars, int length) {
+ // Check whole string without breaking.
+ uint16_t total = 0;
+ for (int i = 0; i < length; i++) {
+ total |= chars[i] >> 8;
+ }
+ if (total != 0) is_one_byte_ = false;
+ }
+
+ private:
+ bool CheckCons(i::ConsString* cons_string) {
+ while (true) {
+ // Check left side if flat.
+ i::String* left = cons_string->first();
+ i::ConsString* left_as_cons =
+ i::String::VisitFlat(this, left, 0);
+ if (!is_one_byte_) return false;
+ // Check right side if flat.
+ i::String* right = cons_string->second();
+ i::ConsString* right_as_cons =
+ i::String::VisitFlat(this, right, 0);
+ if (!is_one_byte_) return false;
+ // Standard recurse/iterate trick.
+ if (left_as_cons != NULL && right_as_cons != NULL) {
+ if (left->length() < right->length()) {
+ CheckCons(left_as_cons);
+ cons_string = right_as_cons;
+ } else {
+ CheckCons(right_as_cons);
+ cons_string = left_as_cons;
+ }
+ // Check fast return.
+ if (!is_one_byte_) return false;
+ continue;
+ }
+ // Descend left in place.
+ if (left_as_cons != NULL) {
+ cons_string = left_as_cons;
+ continue;
+ }
+ // Descend right in place.
+ if (right_as_cons != NULL) {
+ cons_string = right_as_cons;
+ continue;
+ }
+ // Terminate.
+ break;
+ }
+ return is_one_byte_;
+ }
+ bool is_one_byte_;
+ DISALLOW_COPY_AND_ASSIGN(ContainsOnlyOneByteHelper);
+};
+
+
+bool String::ContainsOnlyOneByte() const {
+ i::Handle<i::String> str = Utils::OpenHandle(this);
+ if (IsDeadCheck(str->GetIsolate(),
+ "v8::String::ContainsOnlyOneByte()")) {
+ return false;
+ }
+ if (str->HasOnlyOneByteChars()) return true;
+ ContainsOnlyOneByteHelper helper;
+ return helper.Check(*str);
+}
+
+
class Utf8LengthHelper : public i::AllStatic {
public:
enum State {
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 2fd7170..3fbe0c5 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -30,7 +30,6 @@
#if defined(V8_TARGET_ARCH_ARM)
#include "bootstrapper.h"
-#include "builtins-decls.h"
#include "code-stubs.h"
#include "regexp-macro-assembler.h"
#include "stub-cache.h"
@@ -146,7 +145,7 @@
descriptor->register_params_ = registers;
descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
descriptor->deoptimization_handler_ =
- FUNCTION_ADDR(ArrayConstructor_StubFailure);
+ Runtime::FunctionForId(Runtime::kArrayConstructor)->entry;
}
@@ -168,7 +167,7 @@
descriptor->register_params_ = registers;
descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
descriptor->deoptimization_handler_ =
- FUNCTION_ADDR(InternalArrayConstructor_StubFailure);
+ Runtime::FunctionForId(Runtime::kInternalArrayConstructor)->entry;
}
diff --git a/src/arm/regexp-macro-assembler-arm.cc b/src/arm/regexp-macro-assembler-arm.cc
index 4241502..4d415ef 100644
--- a/src/arm/regexp-macro-assembler-arm.cc
+++ b/src/arm/regexp-macro-assembler-arm.cc
@@ -235,54 +235,6 @@
}
-void RegExpMacroAssemblerARM::CheckCharacters(Vector<const uc16> str,
- int cp_offset,
- Label* on_failure,
- bool check_end_of_string) {
- if (on_failure == NULL) {
- // Instead of inlining a backtrack for each test, (re)use the global
- // backtrack target.
- on_failure = &backtrack_label_;
- }
-
- if (check_end_of_string) {
- // Is last character of required match inside string.
- CheckPosition(cp_offset + str.length() - 1, on_failure);
- }
-
- __ add(r0, end_of_input_address(), Operand(current_input_offset()));
- if (cp_offset != 0) {
- int byte_offset = cp_offset * char_size();
- __ add(r0, r0, Operand(byte_offset));
- }
-
- // r0 : Address of characters to match against str.
- int stored_high_byte = 0;
- for (int i = 0; i < str.length(); i++) {
- if (mode_ == ASCII) {
- __ ldrb(r1, MemOperand(r0, char_size(), PostIndex));
- ASSERT(str[i] <= String::kMaxOneByteCharCode);
- __ cmp(r1, Operand(str[i]));
- } else {
- __ ldrh(r1, MemOperand(r0, char_size(), PostIndex));
- uc16 match_char = str[i];
- int match_high_byte = (match_char >> 8);
- if (match_high_byte == 0) {
- __ cmp(r1, Operand(str[i]));
- } else {
- if (match_high_byte != stored_high_byte) {
- __ mov(r2, Operand(match_high_byte));
- stored_high_byte = match_high_byte;
- }
- __ add(r3, r2, Operand(match_char & 0xff));
- __ cmp(r1, r3);
- }
- }
- BranchOrBacktrack(ne, on_failure);
- }
-}
-
-
void RegExpMacroAssemblerARM::CheckGreedyLoop(Label* on_equal) {
__ ldr(r0, MemOperand(backtrack_stackpointer(), 0));
__ cmp(current_input_offset(), r0);
@@ -556,7 +508,7 @@
case 'd':
// Match ASCII digits ('0'..'9')
__ sub(r0, current_character(), Operand('0'));
- __ cmp(current_character(), Operand('9' - '0'));
+ __ cmp(r0, Operand('9' - '0'));
BranchOrBacktrack(hi, on_no_match);
return true;
case 'D':
diff --git a/src/arm/regexp-macro-assembler-arm.h b/src/arm/regexp-macro-assembler-arm.h
index 921d8f5..1825752 100644
--- a/src/arm/regexp-macro-assembler-arm.h
+++ b/src/arm/regexp-macro-assembler-arm.h
@@ -53,10 +53,6 @@
Label* on_equal);
virtual void CheckCharacterGT(uc16 limit, Label* on_greater);
virtual void CheckCharacterLT(uc16 limit, Label* on_less);
- virtual void CheckCharacters(Vector<const uc16> str,
- int cp_offset,
- Label* on_failure,
- bool check_end_of_string);
// A "greedy loop" is a loop that is both greedy and with a simple
// body. It has a particularly simple implementation.
virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
diff --git a/src/ast.cc b/src/ast.cc
index 8c0351c..b4c0430 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -792,12 +792,12 @@
bool RegExpAssertion::IsAnchoredAtStart() {
- return type() == RegExpAssertion::START_OF_INPUT;
+ return assertion_type() == RegExpAssertion::START_OF_INPUT;
}
bool RegExpAssertion::IsAnchoredAtEnd() {
- return type() == RegExpAssertion::END_OF_INPUT;
+ return assertion_type() == RegExpAssertion::END_OF_INPUT;
}
@@ -929,7 +929,7 @@
void* RegExpUnparser::VisitAssertion(RegExpAssertion* that, void* data) {
- switch (that->type()) {
+ switch (that->assertion_type()) {
case RegExpAssertion::START_OF_INPUT:
stream()->Add("@^i");
break;
diff --git a/src/ast.h b/src/ast.h
index 41c910a..2ffa473b 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -39,7 +39,8 @@
#include "small-pointer-list.h"
#include "smart-pointers.h"
#include "token.h"
-#include "type-info.h"
+#include "type-info.h" // TODO(rossberg): this should eventually be removed
+#include "types.h"
#include "utils.h"
#include "variables.h"
#include "interface.h"
@@ -163,9 +164,9 @@
typedef ZoneList<Handle<Object> > ZoneObjectList;
-#define DECLARE_NODE_TYPE(type) \
- virtual void Accept(AstVisitor* v); \
- virtual AstNode::Type node_type() const { return AstNode::k##type; } \
+#define DECLARE_NODE_TYPE(type) \
+ virtual void Accept(AstVisitor* v); \
+ virtual AstNode::NodeType node_type() const { return AstNode::k##type; } \
template<class> friend class AstNodeFactory;
@@ -197,7 +198,7 @@
class AstNode: public ZoneObject {
public:
#define DECLARE_TYPE_ENUM(type) k##type,
- enum Type {
+ enum NodeType {
AST_NODE_LIST(DECLARE_TYPE_ENUM)
kInvalid = -1
};
@@ -212,7 +213,7 @@
virtual ~AstNode() { }
virtual void Accept(AstVisitor* v) = 0;
- virtual Type node_type() const = 0;
+ virtual NodeType node_type() const = 0;
// Type testing & conversion functions overridden by concrete subclasses.
#define DECLARE_NODE_FUNCTIONS(type) \
@@ -354,6 +355,9 @@
// True iff the expression is the undefined literal.
bool IsUndefinedLiteral();
+ // Expression type
+ Handle<Type> type() { return type_; }
+
// Type feedback information for assignments and properties.
virtual bool IsMonomorphic() {
UNREACHABLE();
@@ -383,10 +387,12 @@
protected:
explicit Expression(Isolate* isolate)
- : id_(GetNextId(isolate)),
+ : type_(Type::Any(), isolate),
+ id_(GetNextId(isolate)),
test_id_(GetNextId(isolate)) {}
private:
+ Handle<Type> type_;
byte to_boolean_types_;
const BailoutId id_;
@@ -396,7 +402,7 @@
class BreakableStatement: public Statement {
public:
- enum Type {
+ enum BreakableType {
TARGET_FOR_ANONYMOUS,
TARGET_FOR_NAMED_ONLY
};
@@ -412,15 +418,18 @@
Label* break_target() { return &break_target_; }
// Testers.
- bool is_target_for_anonymous() const { return type_ == TARGET_FOR_ANONYMOUS; }
+ bool is_target_for_anonymous() const {
+ return breakable_type_ == TARGET_FOR_ANONYMOUS;
+ }
BailoutId EntryId() const { return entry_id_; }
BailoutId ExitId() const { return exit_id_; }
protected:
- BreakableStatement(Isolate* isolate, ZoneStringList* labels, Type type)
+ BreakableStatement(
+ Isolate* isolate, ZoneStringList* labels, BreakableType breakable_type)
: labels_(labels),
- type_(type),
+ breakable_type_(breakable_type),
entry_id_(GetNextId(isolate)),
exit_id_(GetNextId(isolate)) {
ASSERT(labels == NULL || labels->length() > 0);
@@ -429,7 +438,7 @@
private:
ZoneStringList* labels_;
- Type type_;
+ BreakableType breakable_type_;
Label break_target_;
const BailoutId entry_id_;
const BailoutId exit_id_;
@@ -1123,7 +1132,7 @@
// Virtual behaviour. TargetCollectors are never part of the AST.
virtual void Accept(AstVisitor* v) { UNREACHABLE(); }
- virtual Type node_type() const { return kInvalid; }
+ virtual NodeType node_type() const { return kInvalid; }
virtual TargetCollector* AsTargetCollector() { return this; }
ZoneList<Label*>* targets() { return &targets_; }
@@ -2117,7 +2126,7 @@
class FunctionLiteral: public Expression {
public:
- enum Type {
+ enum FunctionType {
ANONYMOUS_EXPRESSION,
NAMED_EXPRESSION,
DECLARATION
@@ -2216,7 +2225,7 @@
int expected_property_count,
int handler_count,
int parameter_count,
- Type type,
+ FunctionType function_type,
ParameterFlag has_duplicate_parameters,
IsFunctionFlag is_function,
IsParenthesizedFlag is_parenthesized,
@@ -2232,8 +2241,8 @@
parameter_count_(parameter_count),
function_token_position_(RelocInfo::kNoPosition) {
bitfield_ =
- IsExpression::encode(type != DECLARATION) |
- IsAnonymous::encode(type == ANONYMOUS_EXPRESSION) |
+ IsExpression::encode(function_type != DECLARATION) |
+ IsAnonymous::encode(function_type == ANONYMOUS_EXPRESSION) |
Pretenure::encode(false) |
HasDuplicateParameters::encode(has_duplicate_parameters) |
IsFunction::encode(is_function) |
@@ -2379,7 +2388,7 @@
class RegExpAssertion: public RegExpTree {
public:
- enum Type {
+ enum AssertionType {
START_OF_LINE,
START_OF_INPUT,
END_OF_LINE,
@@ -2387,7 +2396,7 @@
BOUNDARY,
NON_BOUNDARY
};
- explicit RegExpAssertion(Type type) : type_(type) { }
+ explicit RegExpAssertion(AssertionType type) : assertion_type_(type) { }
virtual void* Accept(RegExpVisitor* visitor, void* data);
virtual RegExpNode* ToNode(RegExpCompiler* compiler,
RegExpNode* on_success);
@@ -2397,9 +2406,9 @@
virtual bool IsAnchoredAtEnd();
virtual int min_match() { return 0; }
virtual int max_match() { return 0; }
- Type type() { return type_; }
+ AssertionType assertion_type() { return assertion_type_; }
private:
- Type type_;
+ AssertionType assertion_type_;
};
@@ -2512,13 +2521,13 @@
class RegExpQuantifier: public RegExpTree {
public:
- enum Type { GREEDY, NON_GREEDY, POSSESSIVE };
- RegExpQuantifier(int min, int max, Type type, RegExpTree* body)
+ enum QuantifierType { GREEDY, NON_GREEDY, POSSESSIVE };
+ RegExpQuantifier(int min, int max, QuantifierType type, RegExpTree* body)
: body_(body),
min_(min),
max_(max),
min_match_(min * body->min_match()),
- type_(type) {
+ quantifier_type_(type) {
if (max > 0 && body->max_match() > kInfinity / max) {
max_match_ = kInfinity;
} else {
@@ -2542,9 +2551,9 @@
virtual int max_match() { return max_match_; }
int min() { return min_; }
int max() { return max_; }
- bool is_possessive() { return type_ == POSSESSIVE; }
- bool is_non_greedy() { return type_ == NON_GREEDY; }
- bool is_greedy() { return type_ == GREEDY; }
+ bool is_possessive() { return quantifier_type_ == POSSESSIVE; }
+ bool is_non_greedy() { return quantifier_type_ == NON_GREEDY; }
+ bool is_greedy() { return quantifier_type_ == GREEDY; }
RegExpTree* body() { return body_; }
private:
@@ -2553,7 +2562,7 @@
int max_;
int min_match_;
int max_match_;
- Type type_;
+ QuantifierType quantifier_type_;
};
@@ -3086,14 +3095,14 @@
int handler_count,
int parameter_count,
FunctionLiteral::ParameterFlag has_duplicate_parameters,
- FunctionLiteral::Type type,
+ FunctionLiteral::FunctionType function_type,
FunctionLiteral::IsFunctionFlag is_function,
FunctionLiteral::IsParenthesizedFlag is_parenthesized,
FunctionLiteral::IsGeneratorFlag is_generator) {
FunctionLiteral* lit = new(zone_) FunctionLiteral(
isolate_, name, scope, body,
materialized_literal_count, expected_property_count, handler_count,
- parameter_count, type, has_duplicate_parameters, is_function,
+ parameter_count, function_type, has_duplicate_parameters, is_function,
is_parenthesized, is_generator);
// Top-level literal doesn't count for the AST's properties.
if (is_function == FunctionLiteral::kIsFunction) {
diff --git a/src/builtins-decls.h b/src/builtins-decls.h
deleted file mode 100644
index 8c038dc..0000000
--- a/src/builtins-decls.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2013 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_BUILTINS_DECLS_H_
-#define V8_BUILTINS_DECLS_H_
-
-#include "arguments.h"
-
-namespace v8 {
-namespace internal {
-
-// TODO(mvstanton): move these to runtime.h/.cc
-DECLARE_RUNTIME_FUNCTION(MaybeObject*, ArrayConstructor_StubFailure);
-DECLARE_RUNTIME_FUNCTION(MaybeObject*, InternalArrayConstructor_StubFailure);
-
-} } // namespace v8::internal
-
-#endif // V8_BUILTINS_DECLS_H_
diff --git a/src/builtins.cc b/src/builtins.cc
index b42fd5a..d97a477 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -194,93 +194,6 @@
}
-static MaybeObject* ArrayConstructorStubFailureCommon(
- Isolate* isolate,
- Handle<JSFunction> constructor,
- Handle<Object> type_info,
- Arguments* caller_args) {
- bool holey = false;
- if (caller_args->length() == 1 && (*caller_args)[0]->IsSmi()) {
- int value = Smi::cast((*caller_args)[0])->value();
- holey = (value > 0 && value < JSObject::kInitialMaxFastElementArray);
- }
-
- JSArray* array;
- MaybeObject* maybe_array;
- if (!type_info.is_null() &&
- *type_info != isolate->heap()->undefined_value() &&
- JSGlobalPropertyCell::cast(*type_info)->value()->IsSmi()) {
- JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(*type_info);
- Smi* smi = Smi::cast(cell->value());
- ElementsKind to_kind = static_cast<ElementsKind>(smi->value());
- if (holey && !IsFastHoleyElementsKind(to_kind)) {
- to_kind = GetHoleyElementsKind(to_kind);
- // Update the allocation site info to reflect the advice alteration.
- cell->set_value(Smi::FromInt(to_kind));
- }
-
- maybe_array = isolate->heap()->AllocateJSObjectWithAllocationSite(
- *constructor, type_info);
- if (!maybe_array->To(&array)) return maybe_array;
- } else {
- maybe_array = isolate->heap()->AllocateJSObject(*constructor);
- if (!maybe_array->To(&array)) return maybe_array;
- // We might need to transition to holey
- ElementsKind kind = constructor->initial_map()->elements_kind();
- if (holey && !IsFastHoleyElementsKind(kind)) {
- kind = GetHoleyElementsKind(kind);
- maybe_array = array->TransitionElementsKind(kind);
- if (maybe_array->IsFailure()) return maybe_array;
- }
- }
-
- maybe_array = isolate->heap()->AllocateJSArrayStorage(array, 0, 0,
- DONT_INITIALIZE_ARRAY_ELEMENTS);
- if (maybe_array->IsFailure()) return maybe_array;
- maybe_array = ArrayConstructInitializeElements(array, caller_args);
- if (maybe_array->IsFailure()) return maybe_array;
- return array;
-}
-
-
-RUNTIME_FUNCTION(MaybeObject*, ArrayConstructor_StubFailure) {
- // If we get 2 arguments then they are the stub parameters (constructor, type
- // info). If we get 3, then the first one is a pointer to the arguments
- // passed by the caller.
- Arguments empty_args(0, NULL);
- bool no_caller_args = args.length() == 2;
- ASSERT(no_caller_args || args.length() == 3);
- int parameters_start = no_caller_args ? 0 : 1;
- Arguments* caller_args = no_caller_args
- ? &empty_args
- : reinterpret_cast<Arguments*>(args[0]);
- Handle<JSFunction> constructor = args.at<JSFunction>(parameters_start);
- Handle<Object> type_info = args.at<Object>(parameters_start + 1);
-
- return ArrayConstructorStubFailureCommon(isolate,
- constructor,
- type_info,
- caller_args);
-}
-
-
-RUNTIME_FUNCTION(MaybeObject*, InternalArrayConstructor_StubFailure) {
- Arguments empty_args(0, NULL);
- bool no_caller_args = args.length() == 1;
- ASSERT(no_caller_args || args.length() == 2);
- int parameters_start = no_caller_args ? 0 : 1;
- Arguments* caller_args = no_caller_args
- ? &empty_args
- : reinterpret_cast<Arguments*>(args[0]);
- Handle<JSFunction> constructor = args.at<JSFunction>(parameters_start);
-
- return ArrayConstructorStubFailureCommon(isolate,
- constructor,
- Handle<Object>::null(),
- caller_args);
-}
-
-
static MaybeObject* ArrayCodeGenericCommon(Arguments* args,
Isolate* isolate,
JSFunction* constructor) {
diff --git a/src/factory.cc b/src/factory.cc
index ab42b19..f963334 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -676,9 +676,9 @@
}
-Handle<Object> Factory::NewTypeError(const char* type,
+Handle<Object> Factory::NewTypeError(const char* message,
Vector< Handle<Object> > args) {
- return NewError("MakeTypeError", type, args);
+ return NewError("MakeTypeError", message, args);
}
@@ -687,9 +687,9 @@
}
-Handle<Object> Factory::NewRangeError(const char* type,
+Handle<Object> Factory::NewRangeError(const char* message,
Vector< Handle<Object> > args) {
- return NewError("MakeRangeError", type, args);
+ return NewError("MakeRangeError", message, args);
}
@@ -698,8 +698,9 @@
}
-Handle<Object> Factory::NewSyntaxError(const char* type, Handle<JSArray> args) {
- return NewError("MakeSyntaxError", type, args);
+Handle<Object> Factory::NewSyntaxError(const char* message,
+ Handle<JSArray> args) {
+ return NewError("MakeSyntaxError", message, args);
}
@@ -708,9 +709,9 @@
}
-Handle<Object> Factory::NewReferenceError(const char* type,
+Handle<Object> Factory::NewReferenceError(const char* message,
Vector< Handle<Object> > args) {
- return NewError("MakeReferenceError", type, args);
+ return NewError("MakeReferenceError", message, args);
}
@@ -720,7 +721,7 @@
Handle<Object> Factory::NewError(const char* maker,
- const char* type,
+ const char* message,
Vector< Handle<Object> > args) {
// Instantiate a closeable HandleScope for EscapeFrom.
v8::HandleScope scope(reinterpret_cast<v8::Isolate*>(isolate()));
@@ -729,24 +730,24 @@
array->set(i, *args[i]);
}
Handle<JSArray> object = NewJSArrayWithElements(array);
- Handle<Object> result = NewError(maker, type, object);
+ Handle<Object> result = NewError(maker, message, object);
return result.EscapeFrom(&scope);
}
-Handle<Object> Factory::NewEvalError(const char* type,
+Handle<Object> Factory::NewEvalError(const char* message,
Vector< Handle<Object> > args) {
- return NewError("MakeEvalError", type, args);
+ return NewError("MakeEvalError", message, args);
}
-Handle<Object> Factory::NewError(const char* type,
+Handle<Object> Factory::NewError(const char* message,
Vector< Handle<Object> > args) {
- return NewError("MakeError", type, args);
+ return NewError("MakeError", message, args);
}
-Handle<String> Factory::EmergencyNewError(const char* type,
+Handle<String> Factory::EmergencyNewError(const char* message,
Handle<JSArray> args) {
const int kBufferSize = 1000;
char buffer[kBufferSize];
@@ -754,8 +755,8 @@
char* p = &buffer[0];
Vector<char> v(buffer, kBufferSize);
- OS::StrNCpy(v, type, space);
- space -= Min(space, strlen(type));
+ OS::StrNCpy(v, message, space);
+ space -= Min(space, strlen(message));
p = &buffer[kBufferSize] - space;
for (unsigned i = 0; i < ARRAY_SIZE(args); i++) {
@@ -784,7 +785,7 @@
Handle<Object> Factory::NewError(const char* maker,
- const char* type,
+ const char* message,
Handle<JSArray> args) {
Handle<String> make_str = InternalizeUtf8String(maker);
Handle<Object> fun_obj(
@@ -793,11 +794,11 @@
// If the builtins haven't been properly configured yet this error
// constructor may not have been defined. Bail out.
if (!fun_obj->IsJSFunction()) {
- return EmergencyNewError(type, args);
+ return EmergencyNewError(message, args);
}
Handle<JSFunction> fun = Handle<JSFunction>::cast(fun_obj);
- Handle<Object> type_obj = InternalizeUtf8String(type);
- Handle<Object> argv[] = { type_obj, args };
+ Handle<Object> message_obj = InternalizeUtf8String(message);
+ Handle<Object> argv[] = { message_obj, args };
// Invoke the JavaScript factory method. If an exception is thrown while
// running the factory method, use the exception as the result.
diff --git a/src/factory.h b/src/factory.h
index 233b3b0..66304a9 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -369,33 +369,33 @@
// Interface for creating error objects.
- Handle<Object> NewError(const char* maker, const char* type,
+ Handle<Object> NewError(const char* maker, const char* message,
Handle<JSArray> args);
- Handle<String> EmergencyNewError(const char* type, Handle<JSArray> args);
- Handle<Object> NewError(const char* maker, const char* type,
+ Handle<String> EmergencyNewError(const char* message, Handle<JSArray> args);
+ Handle<Object> NewError(const char* maker, const char* message,
Vector< Handle<Object> > args);
- Handle<Object> NewError(const char* type,
+ Handle<Object> NewError(const char* message,
Vector< Handle<Object> > args);
Handle<Object> NewError(Handle<String> message);
Handle<Object> NewError(const char* constructor,
Handle<String> message);
- Handle<Object> NewTypeError(const char* type,
+ Handle<Object> NewTypeError(const char* message,
Vector< Handle<Object> > args);
Handle<Object> NewTypeError(Handle<String> message);
- Handle<Object> NewRangeError(const char* type,
+ Handle<Object> NewRangeError(const char* message,
Vector< Handle<Object> > args);
Handle<Object> NewRangeError(Handle<String> message);
- Handle<Object> NewSyntaxError(const char* type, Handle<JSArray> args);
+ Handle<Object> NewSyntaxError(const char* message, Handle<JSArray> args);
Handle<Object> NewSyntaxError(Handle<String> message);
- Handle<Object> NewReferenceError(const char* type,
+ Handle<Object> NewReferenceError(const char* message,
Vector< Handle<Object> > args);
Handle<Object> NewReferenceError(Handle<String> message);
- Handle<Object> NewEvalError(const char* type,
+ Handle<Object> NewEvalError(const char* message,
Vector< Handle<Object> > args);
diff --git a/src/handles-inl.h b/src/handles-inl.h
index 9d38f38..4f4490b 100644
--- a/src/handles-inl.h
+++ b/src/handles-inl.h
@@ -57,7 +57,8 @@
if (location_ == other.location_) return true;
if (location_ == NULL || other.location_ == NULL) return false;
// Dereferencing deferred handles to check object equality is safe.
- SLOW_ASSERT(IsDereferenceAllowed(true) && other.IsDereferenceAllowed(true));
+ SLOW_ASSERT(IsDereferenceAllowed(NO_DEFERRED_CHECK) &&
+ other.IsDereferenceAllowed(NO_DEFERRED_CHECK));
return *location_ == *other.location_;
}
@@ -65,20 +66,21 @@
template <typename T>
inline T* Handle<T>::operator*() const {
ASSERT(location_ != NULL && !(*location_)->IsFailure());
- SLOW_ASSERT(IsDereferenceAllowed(false));
+ SLOW_ASSERT(IsDereferenceAllowed(INCLUDE_DEFERRED_CHECK));
return *BitCast<T**>(location_);
}
template <typename T>
inline T** Handle<T>::location() const {
ASSERT(location_ == NULL || !(*location_)->IsFailure());
- SLOW_ASSERT(location_ == NULL || IsDereferenceAllowed(false));
+ SLOW_ASSERT(location_ == NULL ||
+ IsDereferenceAllowed(INCLUDE_DEFERRED_CHECK));
return location_;
}
#ifdef DEBUG
template <typename T>
-bool Handle<T>::IsDereferenceAllowed(bool explicitly_allow_deferred) const {
+bool Handle<T>::IsDereferenceAllowed(DereferenceCheckMode mode) const {
ASSERT(location_ != NULL);
Object* object = *BitCast<T**>(location_);
if (object->IsSmi()) return true;
@@ -91,7 +93,7 @@
return true;
}
if (!AllowHandleDereference::IsAllowed()) return false;
- if (!explicitly_allow_deferred &&
+ if (mode == INCLUDE_DEFERRED_CHECK &&
!AllowDeferredHandleDereference::IsAllowed()) {
// Accessing maps and internalized strings is safe.
if (heap_object->IsMap()) return true;
diff --git a/src/handles.h b/src/handles.h
index 573298a..0cd4f5b 100644
--- a/src/handles.h
+++ b/src/handles.h
@@ -61,7 +61,7 @@
location_ = reinterpret_cast<T**>(handle.location_);
}
- INLINE(T* operator ->() const) { return operator*(); }
+ INLINE(T* operator->() const) { return operator*(); }
// Check if this handle refers to the exact same object as the other handle.
INLINE(bool is_identical_to(const Handle<T> other) const);
@@ -85,7 +85,9 @@
inline Handle<T> EscapeFrom(v8::HandleScope* scope);
#ifdef DEBUG
- bool IsDereferenceAllowed(bool explicitly_allow_deferred) const;
+ enum DereferenceCheckMode { INCLUDE_DEFERRED_CHECK, NO_DEFERRED_CHECK };
+
+ bool IsDereferenceAllowed(DereferenceCheckMode mode) const;
#endif // DEBUG
private:
diff --git a/src/heap.cc b/src/heap.cc
index 5e88aca..6a89efd 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -151,6 +151,7 @@
last_idle_notification_gc_count_(0),
last_idle_notification_gc_count_init_(false),
mark_sweeps_since_idle_round_started_(0),
+ ms_count_at_last_idle_notification_(0),
gc_count_at_last_idle_gc_(0),
scavenges_since_last_idle_round_(kIdleScavengeThreshold),
gcs_since_last_deopt_(0),
@@ -5707,7 +5708,6 @@
uncommit = true;
}
CollectAllGarbage(kNoGCFlags, "idle notification: finalize incremental");
- mark_sweeps_since_idle_round_started_++;
gc_count_at_last_idle_gc_ = gc_count_;
if (uncommit) {
new_space_.Shrink();
@@ -5783,9 +5783,18 @@
}
}
+ int new_mark_sweeps = ms_count_ - ms_count_at_last_idle_notification_;
+ mark_sweeps_since_idle_round_started_ += new_mark_sweeps;
+ ms_count_at_last_idle_notification_ = ms_count_;
+
int remaining_mark_sweeps = kMaxMarkSweepsInIdleRound -
mark_sweeps_since_idle_round_started_;
+ if (remaining_mark_sweeps <= 0) {
+ FinishIdleRound();
+ return true;
+ }
+
if (incremental_marking()->IsStopped()) {
// If there are no more than two GCs left in this idle round and we are
// allowed to do a full GC, then make those GCs full in order to compact
@@ -5795,7 +5804,6 @@
if (remaining_mark_sweeps <= 2 && hint >= kMinHintForFullGC) {
CollectAllGarbage(kReduceMemoryFootprintMask,
"idle notification: finalize idle round");
- mark_sweeps_since_idle_round_started_++;
} else {
incremental_marking()->Start();
}
@@ -5803,12 +5811,6 @@
if (!incremental_marking()->IsStopped()) {
AdvanceIdleIncrementalMarking(step_size);
}
-
- if (mark_sweeps_since_idle_round_started_ >= kMaxMarkSweepsInIdleRound) {
- FinishIdleRound();
- return true;
- }
-
return false;
}
diff --git a/src/heap.h b/src/heap.h
index 394a02a..6d04454 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -2261,6 +2261,7 @@
void StartIdleRound() {
mark_sweeps_since_idle_round_started_ = 0;
+ ms_count_at_last_idle_notification_ = ms_count_;
}
void FinishIdleRound() {
@@ -2337,6 +2338,7 @@
bool last_idle_notification_gc_count_init_;
int mark_sweeps_since_idle_round_started_;
+ int ms_count_at_last_idle_notification_;
unsigned int gc_count_at_last_idle_gc_;
int scavenges_since_last_idle_round_;
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index 5fae5f7..d3f1a9e 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -2498,8 +2498,10 @@
Representation observed_left = observed_input_representation(0);
Representation observed_right = observed_input_representation(1);
- Representation rep = Representation::Smi();
- if (observed_left.IsInteger32() && observed_right.IsInteger32()) {
+ Representation rep = Representation::None();
+ rep = rep.generalize(observed_left);
+ rep = rep.generalize(observed_right);
+ if (rep.IsNone() || rep.IsSmiOrInteger32()) {
if (!left_rep.IsTagged()) rep = rep.generalize(left_rep);
if (!right_rep.IsTagged()) rep = rep.generalize(right_rep);
} else {
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 5da6d52..d1cfb8e 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -898,13 +898,11 @@
HValue* HGraphBuilder::LoopBuilder::BeginBody(
HValue* initial,
HValue* terminating,
- Token::Value token,
- Representation input_representation) {
+ Token::Value token) {
HEnvironment* env = builder_->environment();
phi_ = new(zone()) HPhi(env->values()->length(), zone());
header_block_->AddPhi(phi_);
phi_->AddInput(initial);
- phi_->AssumeRepresentation(Representation::Integer32());
env->Push(initial);
builder_->current_block()->GotoNoSimulate(header_block_);
@@ -918,9 +916,6 @@
builder_->set_current_block(header_block_);
HCompareIDAndBranch* compare =
new(zone()) HCompareIDAndBranch(phi_, terminating, token);
- compare->set_observed_input_representation(input_representation,
- input_representation);
- compare->AssumeRepresentation(input_representation);
compare->SetSuccessorAt(0, body_block_);
compare->SetSuccessorAt(1, exit_block_);
builder_->current_block()->Finish(compare);
@@ -934,7 +929,6 @@
increment_ = HSub::New(zone(), context_, phi_, one);
}
increment_->ClearFlag(HValue::kCanOverflow);
- increment_->AssumeRepresentation(Representation::Integer32());
builder_->AddInstruction(increment_);
return increment_;
} else {
@@ -954,7 +948,6 @@
increment_ = HSub::New(zone(), context_, phi_, one);
}
increment_->ClearFlag(HValue::kCanOverflow);
- increment_->AssumeRepresentation(Representation::Integer32());
builder_->AddInstruction(increment_);
}
diff --git a/src/hydrogen.h b/src/hydrogen.h
index db607d5..5cb99a1 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -1217,8 +1217,7 @@
HValue* BeginBody(
HValue* initial,
HValue* terminating,
- Token::Value token,
- Representation input_representation = Representation::Integer32());
+ Token::Value token);
void EndBody();
private:
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index 8cb4725..ad1c65d 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -30,7 +30,6 @@
#if defined(V8_TARGET_ARCH_IA32)
#include "bootstrapper.h"
-#include "builtins-decls.h"
#include "code-stubs.h"
#include "isolate.h"
#include "jsregexp.h"
@@ -138,7 +137,7 @@
descriptor->register_params_ = registers;
descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
descriptor->deoptimization_handler_ =
- FUNCTION_ADDR(ArrayConstructor_StubFailure);
+ Runtime::FunctionForId(Runtime::kArrayConstructor)->entry;
}
@@ -160,7 +159,7 @@
descriptor->register_params_ = registers;
descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
descriptor->deoptimization_handler_ =
- FUNCTION_ADDR(InternalArrayConstructor_StubFailure);
+ Runtime::FunctionForId(Runtime::kInternalArrayConstructor)->entry;
}
@@ -7766,14 +7765,16 @@
void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
// Ecx is the only volatile register we must save.
+ const int kNumSavedRegisters = 1;
__ push(ecx);
// Calculate and push the original stack pointer.
- __ lea(eax, Operand(esp, kPointerSize));
+ __ lea(eax, Operand(esp, (kNumSavedRegisters + 1) * kPointerSize));
__ push(eax);
- // Calculate and push the function address.
- __ mov(eax, Operand(eax, 0));
+ // Retrieve our return address and use it to calculate the calling
+ // function's address.
+ __ mov(eax, Operand(esp, (kNumSavedRegisters + 1) * kPointerSize));
__ sub(eax, Immediate(Assembler::kCallInstructionLength));
__ push(eax);
diff --git a/src/ia32/regexp-macro-assembler-ia32.cc b/src/ia32/regexp-macro-assembler-ia32.cc
index d635fe1..397ebde 100644
--- a/src/ia32/regexp-macro-assembler-ia32.cc
+++ b/src/ia32/regexp-macro-assembler-ia32.cc
@@ -209,86 +209,6 @@
}
-void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str,
- int cp_offset,
- Label* on_failure,
- bool check_end_of_string) {
-#ifdef DEBUG
- // If input is ASCII, don't even bother calling here if the string to
- // match contains a non-ASCII character.
- if (mode_ == ASCII) {
- ASSERT(String::IsOneByte(str.start(), str.length()));
- }
-#endif
- int byte_length = str.length() * char_size();
- int byte_offset = cp_offset * char_size();
- if (check_end_of_string) {
- // Check that there are at least str.length() characters left in the input.
- __ cmp(edi, Immediate(-(byte_offset + byte_length)));
- BranchOrBacktrack(greater, on_failure);
- }
-
- if (on_failure == NULL) {
- // Instead of inlining a backtrack, (re)use the global backtrack target.
- on_failure = &backtrack_label_;
- }
-
- // Do one character test first to minimize loading for the case that
- // we don't match at all (loading more than one character introduces that
- // chance of reading unaligned and reading across cache boundaries).
- // If the first character matches, expect a larger chance of matching the
- // string, and start loading more characters at a time.
- if (mode_ == ASCII) {
- __ cmpb(Operand(esi, edi, times_1, byte_offset),
- static_cast<int8_t>(str[0]));
- } else {
- // Don't use 16-bit immediate. The size changing prefix throws off
- // pre-decoding.
- __ movzx_w(eax,
- Operand(esi, edi, times_1, byte_offset));
- __ cmp(eax, static_cast<int32_t>(str[0]));
- }
- BranchOrBacktrack(not_equal, on_failure);
-
- __ lea(ebx, Operand(esi, edi, times_1, 0));
- for (int i = 1, n = str.length(); i < n;) {
- if (mode_ == ASCII) {
- if (i <= n - 4) {
- int combined_chars =
- (static_cast<uint32_t>(str[i + 0]) << 0) |
- (static_cast<uint32_t>(str[i + 1]) << 8) |
- (static_cast<uint32_t>(str[i + 2]) << 16) |
- (static_cast<uint32_t>(str[i + 3]) << 24);
- __ cmp(Operand(ebx, byte_offset + i), Immediate(combined_chars));
- i += 4;
- } else {
- __ cmpb(Operand(ebx, byte_offset + i),
- static_cast<int8_t>(str[i]));
- i += 1;
- }
- } else {
- ASSERT(mode_ == UC16);
- if (i <= n - 2) {
- __ cmp(Operand(ebx, byte_offset + i * sizeof(uc16)),
- Immediate(*reinterpret_cast<const int*>(&str[i])));
- i += 2;
- } else {
- // Avoid a 16-bit immediate operation. It uses the length-changing
- // 0x66 prefix which causes pre-decoder misprediction and pipeline
- // stalls. See
- // "Intel(R) 64 and IA-32 Architectures Optimization Reference Manual"
- // (248966.pdf) section 3.4.2.3 "Length-Changing Prefixes (LCP)"
- __ movzx_w(eax,
- Operand(ebx, byte_offset + i * sizeof(uc16)));
- __ cmp(eax, static_cast<int32_t>(str[i]));
- i += 1;
- }
- }
- BranchOrBacktrack(not_equal, on_failure);
- }
-}
-
-
void RegExpMacroAssemblerIA32::CheckGreedyLoop(Label* on_equal) {
Label fallthrough;
__ cmp(edi, Operand(backtrack_stackpointer(), 0));
diff --git a/src/ia32/regexp-macro-assembler-ia32.h b/src/ia32/regexp-macro-assembler-ia32.h
index 6040d80..3933336 100644
--- a/src/ia32/regexp-macro-assembler-ia32.h
+++ b/src/ia32/regexp-macro-assembler-ia32.h
@@ -52,10 +52,6 @@
Label* on_equal);
virtual void CheckCharacterGT(uc16 limit, Label* on_greater);
virtual void CheckCharacterLT(uc16 limit, Label* on_less);
- virtual void CheckCharacters(Vector<const uc16> str,
- int cp_offset,
- Label* on_failure,
- bool check_end_of_string);
// A "greedy loop" is a loop that is both greedy and with a simple
// body. It has a particularly simple implementation.
virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index f32ab13..7838c04 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -950,10 +950,10 @@
int TextElement::length() {
- if (type == ATOM) {
+ if (text_type == ATOM) {
return data.u_atom->length();
} else {
- ASSERT(type == CHAR_CLASS);
+ ASSERT(text_type == CHAR_CLASS);
return 1;
}
}
@@ -1165,7 +1165,7 @@
bool Trace::DeferredAction::Mentions(int that) {
- if (type() == ActionNode::CLEAR_CAPTURES) {
+ if (action_type() == ActionNode::CLEAR_CAPTURES) {
Interval range = static_cast<DeferredClearCaptures*>(this)->range();
return range.Contains(that);
} else {
@@ -1191,7 +1191,7 @@
action != NULL;
action = action->next()) {
if (action->Mentions(reg)) {
- if (action->type() == ActionNode::STORE_POSITION) {
+ if (action->action_type() == ActionNode::STORE_POSITION) {
*cp_offset = static_cast<DeferredCapture*>(action)->cp_offset();
return true;
} else {
@@ -1209,7 +1209,7 @@
for (DeferredAction* action = actions_;
action != NULL;
action = action->next()) {
- if (action->type() == ActionNode::CLEAR_CAPTURES) {
+ if (action->action_type() == ActionNode::CLEAR_CAPTURES) {
Interval range = static_cast<DeferredClearCaptures*>(action)->range();
for (int i = range.from(); i <= range.to(); i++)
affected_registers->Set(i, zone);
@@ -1273,7 +1273,7 @@
action != NULL;
action = action->next()) {
if (action->Mentions(reg)) {
- switch (action->type()) {
+ switch (action->action_type()) {
case ActionNode::SET_REGISTER: {
Trace::DeferredSetRegister* psr =
static_cast<Trace::DeferredSetRegister*>(action);
@@ -2304,7 +2304,7 @@
int budget,
bool not_at_start) {
if (budget <= 0) return 0;
- if (type_ == POSITIVE_SUBMATCH_SUCCESS) return 0; // Rewinds input!
+ if (action_type_ == POSITIVE_SUBMATCH_SUCCESS) return 0; // Rewinds input!
return on_success()->EatsAtLeast(still_to_find,
budget - 1,
not_at_start);
@@ -2315,9 +2315,9 @@
int budget,
BoyerMooreLookahead* bm,
bool not_at_start) {
- if (type_ == BEGIN_SUBMATCH) {
+ if (action_type_ == BEGIN_SUBMATCH) {
bm->SetRest(offset);
- } else if (type_ != POSITIVE_SUBMATCH_SUCCESS) {
+ } else if (action_type_ != POSITIVE_SUBMATCH_SUCCESS) {
on_success()->FillInBMInfo(offset, budget - 1, bm, not_at_start);
}
SaveBMInfo(bm, not_at_start, offset);
@@ -2333,7 +2333,7 @@
// implies false. So lets just return the max answer (still_to_find) since
// that won't prevent us from preloading a lot of characters for the other
// branches in the node graph.
- if (type() == AT_START && not_at_start) return still_to_find;
+ if (assertion_type() == AT_START && not_at_start) return still_to_find;
return on_success()->EatsAtLeast(still_to_find,
budget - 1,
not_at_start);
@@ -2345,7 +2345,7 @@
BoyerMooreLookahead* bm,
bool not_at_start) {
// Match the behaviour of EatsAtLeast on this node.
- if (type() == AT_START && not_at_start) return;
+ if (assertion_type() == AT_START && not_at_start) return;
on_success()->FillInBMInfo(offset, budget - 1, bm, not_at_start);
SaveBMInfo(bm, not_at_start, offset);
}
@@ -2562,7 +2562,7 @@
}
for (int k = 0; k < elms_->length(); k++) {
TextElement elm = elms_->at(k);
- if (elm.type == TextElement::ATOM) {
+ if (elm.text_type == TextElement::ATOM) {
Vector<const uc16> quarks = elm.data.u_atom->data();
for (int i = 0; i < characters && i < quarks.length(); i++) {
QuickCheckDetails::Position* pos =
@@ -2815,7 +2815,7 @@
int element_count = elms_->length();
for (int i = 0; i < element_count; i++) {
TextElement elm = elms_->at(i);
- if (elm.type == TextElement::ATOM) {
+ if (elm.text_type == TextElement::ATOM) {
Vector<const uc16> quarks = elm.data.u_atom->data();
for (int j = 0; j < quarks.length(); j++) {
uint16_t c = quarks[j];
@@ -2831,7 +2831,7 @@
copy[j] = converted;
}
} else {
- ASSERT(elm.type == TextElement::CHAR_CLASS);
+ ASSERT(elm.text_type == TextElement::CHAR_CLASS);
RegExpCharacterClass* cc = elm.data.u_char_class;
ZoneList<CharacterRange>* ranges = cc->ranges(zone());
if (!CharacterRange::IsCanonical(ranges)) {
@@ -3086,7 +3086,7 @@
if (lookahead->at(0)->is_non_word()) next_is_word_character = Trace::FALSE;
if (lookahead->at(0)->is_word()) next_is_word_character = Trace::TRUE;
}
- bool at_boundary = (type_ == AssertionNode::AT_BOUNDARY);
+ bool at_boundary = (assertion_type_ == AssertionNode::AT_BOUNDARY);
if (next_is_word_character == Trace::UNKNOWN) {
Label before_non_word;
Label before_word;
@@ -3149,7 +3149,7 @@
RegExpCompiler* compiler,
int filled_in,
bool not_at_start) {
- if (type_ == AT_START && not_at_start) {
+ if (assertion_type_ == AT_START && not_at_start) {
details->set_cannot_match();
return;
}
@@ -3162,7 +3162,7 @@
void AssertionNode::Emit(RegExpCompiler* compiler, Trace* trace) {
RegExpMacroAssembler* assembler = compiler->macro_assembler();
- switch (type_) {
+ switch (assertion_type_) {
case AT_END: {
Label ok;
assembler->CheckPosition(trace->cp_offset(), &ok);
@@ -3255,7 +3255,7 @@
for (int i = preloaded ? 0 : element_count - 1; i >= 0; i--) {
TextElement elm = elms_->at(i);
int cp_offset = trace->cp_offset() + elm.cp_offset;
- if (elm.type == TextElement::ATOM) {
+ if (elm.text_type == TextElement::ATOM) {
Vector<const uc16> quarks = elm.data.u_atom->data();
for (int j = preloaded ? 0 : quarks.length() - 1; j >= 0; j--) {
if (first_element_checked && i == 0 && j == 0) continue;
@@ -3293,7 +3293,7 @@
}
}
} else {
- ASSERT_EQ(elm.type, TextElement::CHAR_CLASS);
+ ASSERT_EQ(elm.text_type, TextElement::CHAR_CLASS);
if (pass == CHARACTER_CLASS_MATCH) {
if (first_element_checked && i == 0) continue;
if (DeterminedAlready(quick_check, elm.cp_offset)) continue;
@@ -3316,7 +3316,7 @@
int TextNode::Length() {
TextElement elm = elms_->last();
ASSERT(elm.cp_offset >= 0);
- if (elm.type == TextElement::ATOM) {
+ if (elm.text_type == TextElement::ATOM) {
return elm.cp_offset + elm.data.u_atom->data().length();
} else {
return elm.cp_offset + 1;
@@ -3422,7 +3422,7 @@
int element_count = elms_->length();
for (int i = 0; i < element_count; i++) {
TextElement elm = elms_->at(i);
- if (elm.type == TextElement::CHAR_CLASS) {
+ if (elm.text_type == TextElement::CHAR_CLASS) {
RegExpCharacterClass* cc = elm.data.u_char_class;
// None of the standard character classes is different in the case
// independent case and it slows us down if we don't know that.
@@ -3439,7 +3439,7 @@
int TextNode::GreedyLoopTextLength() {
TextElement elm = elms_->at(elms_->length() - 1);
- if (elm.type == TextElement::CHAR_CLASS) {
+ if (elm.text_type == TextElement::CHAR_CLASS) {
return elm.cp_offset + 1;
} else {
return elm.cp_offset + elm.data.u_atom->data().length();
@@ -3451,7 +3451,7 @@
RegExpCompiler* compiler) {
if (elms_->length() != 1) return NULL;
TextElement elm = elms_->at(0);
- if (elm.type != TextElement::CHAR_CLASS) return NULL;
+ if (elm.text_type != TextElement::CHAR_CLASS) return NULL;
RegExpCharacterClass* node = elm.data.u_char_class;
ZoneList<CharacterRange>* ranges = node->ranges(zone());
if (!CharacterRange::IsCanonical(ranges)) {
@@ -4196,7 +4196,7 @@
RecursionCheck rc(compiler);
- switch (type_) {
+ switch (action_type_) {
case STORE_POSITION: {
Trace::DeferredCapture
new_capture(data_.u_position_register.reg,
@@ -4526,7 +4526,7 @@
for (int i = 0; i < that->elements()->length(); i++) {
if (i > 0) stream()->Add(" ");
TextElement elm = that->elements()->at(i);
- switch (elm.type) {
+ switch (elm.text_type) {
case TextElement::ATOM: {
stream()->Add("'%w'", elm.data.u_atom->data());
break;
@@ -4573,7 +4573,7 @@
void DotPrinter::VisitAssertion(AssertionNode* that) {
stream()->Add(" n%p [", that);
- switch (that->type()) {
+ switch (that->assertion_type()) {
case AssertionNode::AT_END:
stream()->Add("label=\"$\", shape=septagon");
break;
@@ -4600,7 +4600,7 @@
void DotPrinter::VisitAction(ActionNode* that) {
stream()->Add(" n%p [", that);
- switch (that->type_) {
+ switch (that->action_type_) {
case ActionNode::SET_REGISTER:
stream()->Add("label=\"$%i:=%i\", shape=octagon",
that->data_.u_store_register.reg,
@@ -5013,7 +5013,7 @@
NodeInfo info;
Zone* zone = compiler->zone();
- switch (type()) {
+ switch (assertion_type()) {
case START_OF_LINE:
return AssertionNode::AfterNewline(on_success);
case START_OF_INPUT:
@@ -5715,7 +5715,7 @@
for (int i = 0; i < element_count; i++) {
TextElement& elm = elements()->at(i);
elm.cp_offset = cp_offset;
- if (elm.type == TextElement::ATOM) {
+ if (elm.text_type == TextElement::ATOM) {
cp_offset += elm.data.u_atom->data().length();
} else {
cp_offset++;
@@ -5835,7 +5835,7 @@
return;
}
TextElement text = elements()->at(i);
- if (text.type == TextElement::ATOM) {
+ if (text.text_type == TextElement::ATOM) {
RegExpAtom* atom = text.data.u_atom;
for (int j = 0; j < atom->length(); j++, offset++) {
if (offset >= bm->length()) {
@@ -5858,7 +5858,7 @@
}
}
} else {
- ASSERT(text.type == TextElement::CHAR_CLASS);
+ ASSERT(text.text_type == TextElement::CHAR_CLASS);
RegExpCharacterClass* char_class = text.data.u_char_class;
ZoneList<CharacterRange>* ranges = char_class->ranges(zone());
if (char_class->is_negated()) {
@@ -5971,7 +5971,7 @@
void DispatchTableConstructor::VisitText(TextNode* that) {
TextElement elm = that->elements()->at(0);
- switch (elm.type) {
+ switch (elm.text_type) {
case TextElement::ATOM: {
uc16 c = elm.data.u_atom->data()[0];
AddRange(CharacterRange(c, c));
diff --git a/src/jsregexp.h b/src/jsregexp.h
index 625f192..181a1b2 100644
--- a/src/jsregexp.h
+++ b/src/jsregexp.h
@@ -429,13 +429,13 @@
class TextElement {
public:
- enum Type {UNINITIALIZED, ATOM, CHAR_CLASS};
- TextElement() : type(UNINITIALIZED) { }
- explicit TextElement(Type t) : type(t), cp_offset(-1) { }
+ enum TextType {UNINITIALIZED, ATOM, CHAR_CLASS};
+ TextElement() : text_type(UNINITIALIZED) { }
+ explicit TextElement(TextType t) : text_type(t), cp_offset(-1) { }
static TextElement Atom(RegExpAtom* atom);
static TextElement CharClass(RegExpCharacterClass* char_class);
int length();
- Type type;
+ TextType text_type;
union {
RegExpAtom* u_atom;
RegExpCharacterClass* u_char_class;
@@ -739,7 +739,7 @@
class ActionNode: public SeqRegExpNode {
public:
- enum Type {
+ enum ActionType {
SET_REGISTER,
INCREMENT_REGISTER,
STORE_POSITION,
@@ -780,7 +780,7 @@
int budget,
BoyerMooreLookahead* bm,
bool not_at_start);
- Type type() { return type_; }
+ ActionType action_type() { return action_type_; }
// TODO(erikcorry): We should allow some action nodes in greedy loops.
virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; }
@@ -813,10 +813,10 @@
int range_to;
} u_clear_captures;
} data_;
- ActionNode(Type type, RegExpNode* on_success)
+ ActionNode(ActionType action_type, RegExpNode* on_success)
: SeqRegExpNode(on_success),
- type_(type) { }
- Type type_;
+ action_type_(action_type) { }
+ ActionType action_type_;
friend class DotPrinter;
};
@@ -876,7 +876,7 @@
class AssertionNode: public SeqRegExpNode {
public:
- enum AssertionNodeType {
+ enum AssertionType {
AT_END,
AT_START,
AT_BOUNDARY,
@@ -909,8 +909,7 @@
int budget,
BoyerMooreLookahead* bm,
bool not_at_start);
- AssertionNodeType type() { return type_; }
- void set_type(AssertionNodeType type) { type_ = type; }
+ AssertionType assertion_type() { return assertion_type_; }
private:
void EmitBoundaryCheck(RegExpCompiler* compiler, Trace* trace);
@@ -918,9 +917,9 @@
void BacktrackIfPrevious(RegExpCompiler* compiler,
Trace* trace,
IfPrevious backtrack_if_previous);
- AssertionNode(AssertionNodeType t, RegExpNode* on_success)
- : SeqRegExpNode(on_success), type_(t) { }
- AssertionNodeType type_;
+ AssertionNode(AssertionType t, RegExpNode* on_success)
+ : SeqRegExpNode(on_success), assertion_type_(t) { }
+ AssertionType assertion_type_;
};
@@ -1337,14 +1336,14 @@
class DeferredAction {
public:
- DeferredAction(ActionNode::Type type, int reg)
- : type_(type), reg_(reg), next_(NULL) { }
+ DeferredAction(ActionNode::ActionType action_type, int reg)
+ : action_type_(action_type), reg_(reg), next_(NULL) { }
DeferredAction* next() { return next_; }
bool Mentions(int reg);
int reg() { return reg_; }
- ActionNode::Type type() { return type_; }
+ ActionNode::ActionType action_type() { return action_type_; }
private:
- ActionNode::Type type_;
+ ActionNode::ActionType action_type_;
int reg_;
DeferredAction* next_;
friend class Trace;
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index b738648..1a00bc0 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -30,7 +30,6 @@
#if defined(V8_TARGET_ARCH_MIPS)
#include "bootstrapper.h"
-#include "builtins-decls.h"
#include "code-stubs.h"
#include "codegen.h"
#include "regexp-macro-assembler.h"
@@ -147,7 +146,7 @@
descriptor->register_params_ = registers;
descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
descriptor->deoptimization_handler_ =
- FUNCTION_ADDR(ArrayConstructor_StubFailure);
+ Runtime::FunctionForId(Runtime::kArrayConstructor)->entry;
}
@@ -169,7 +168,7 @@
descriptor->register_params_ = registers;
descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
descriptor->deoptimization_handler_ =
- FUNCTION_ADDR(InternalArrayConstructor_StubFailure);
+ Runtime::FunctionForId(Runtime::kInternalArrayConstructor)->entry;
}
diff --git a/src/mips/regexp-macro-assembler-mips.cc b/src/mips/regexp-macro-assembler-mips.cc
index 3e255b7..977f050 100644
--- a/src/mips/regexp-macro-assembler-mips.cc
+++ b/src/mips/regexp-macro-assembler-mips.cc
@@ -235,55 +235,6 @@
}
-void RegExpMacroAssemblerMIPS::CheckCharacters(Vector<const uc16> str,
- int cp_offset,
- Label* on_failure,
- bool check_end_of_string) {
- if (on_failure == NULL) {
- // Instead of inlining a backtrack for each test, (re)use the global
- // backtrack target.
- on_failure = &backtrack_label_;
- }
-
- if (check_end_of_string) {
- // Is last character of required match inside string.
- CheckPosition(cp_offset + str.length() - 1, on_failure);
- }
-
- __ Addu(a0, end_of_input_address(), Operand(current_input_offset()));
- if (cp_offset != 0) {
- int byte_offset = cp_offset * char_size();
- __ Addu(a0, a0, Operand(byte_offset));
- }
-
- // a0 : Address of characters to match against str.
- int stored_high_byte = 0;
- for (int i = 0; i < str.length(); i++) {
- if (mode_ == ASCII) {
- __ lbu(a1, MemOperand(a0, 0));
- __ addiu(a0, a0, char_size());
- ASSERT(str[i] <= String::kMaxOneByteCharCode);
- BranchOrBacktrack(on_failure, ne, a1, Operand(str[i]));
- } else {
- __ lhu(a1, MemOperand(a0, 0));
- __ addiu(a0, a0, char_size());
- uc16 match_char = str[i];
- int match_high_byte = (match_char >> 8);
- if (match_high_byte == 0) {
- BranchOrBacktrack(on_failure, ne, a1, Operand(str[i]));
- } else {
- if (match_high_byte != stored_high_byte) {
- __ li(a2, Operand(match_high_byte));
- stored_high_byte = match_high_byte;
- }
- __ Addu(a3, a2, Operand(match_char & 0xff));
- BranchOrBacktrack(on_failure, ne, a1, Operand(a3));
- }
- }
- }
-}
-
-
void RegExpMacroAssemblerMIPS::CheckGreedyLoop(Label* on_equal) {
Label backtrack_non_equal;
__ lw(a0, MemOperand(backtrack_stackpointer(), 0));
diff --git a/src/mips/regexp-macro-assembler-mips.h b/src/mips/regexp-macro-assembler-mips.h
index 3ad64f9..86ae4d4 100644
--- a/src/mips/regexp-macro-assembler-mips.h
+++ b/src/mips/regexp-macro-assembler-mips.h
@@ -55,10 +55,6 @@
Label* on_equal);
virtual void CheckCharacterGT(uc16 limit, Label* on_greater);
virtual void CheckCharacterLT(uc16 limit, Label* on_less);
- virtual void CheckCharacters(Vector<const uc16> str,
- int cp_offset,
- Label* on_failure,
- bool check_end_of_string);
// A "greedy loop" is a loop that is both greedy and with a simple
// body. It has a particularly simple implementation.
virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index 549c9ff..8eab562 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -540,6 +540,8 @@
case JS_FUNCTION_TYPE: return "JS_FUNCTION";
case CODE_TYPE: return "CODE";
case JS_ARRAY_TYPE: return "JS_ARRAY";
+ case JS_ARRAY_BUFFER_TYPE: return "JS_ARRAY_BUFFER";
+ case JS_TYPED_ARRAY_TYPE: return "JS_TYPED_ARRAY";
case JS_PROXY_TYPE: return "JS_PROXY";
case JS_WEAK_MAP_TYPE: return "JS_WEAK_MAP";
case JS_REGEXP_TYPE: return "JS_REGEXP";
@@ -822,7 +824,7 @@
byte_offset()->ShortPrint(out);
PrintF(out, "\n - byte_length = ");
byte_length()->ShortPrint(out);
- PrintF(out, " - length = ");
+ PrintF(out, "\n - length = ");
length()->ShortPrint(out);
PrintF("\n");
PrintElements(out);
diff --git a/src/objects.cc b/src/objects.cc
index ca1c650..24c60ec 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -1205,6 +1205,11 @@
if (FLAG_enable_slow_asserts) {
// Assert that the resource and the string are equivalent.
ASSERT(static_cast<size_t>(this->length()) == resource->length());
+ if (this->IsTwoByteRepresentation()) {
+ ScopedVector<uint16_t> smart_chars(this->length());
+ String::WriteToFlat(this, smart_chars.start(), 0, this->length());
+ ASSERT(String::IsOneByte(smart_chars.start(), this->length()));
+ }
ScopedVector<char> smart_chars(this->length());
String::WriteToFlat(this, smart_chars.start(), 0, this->length());
ASSERT(memcmp(smart_chars.start(),
diff --git a/src/objects.h b/src/objects.h
index a16ebbf..b7b32f8 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -3677,7 +3677,7 @@
static inline ScopeInfo* cast(Object* object);
// Return the type of this scope.
- ScopeType Type();
+ ScopeType scope_type();
// Does this scope call eval?
bool CallsEval();
@@ -3860,7 +3860,7 @@
};
// Properties of scopes.
- class TypeField: public BitField<ScopeType, 0, 3> {};
+ class ScopeTypeField: public BitField<ScopeType, 0, 3> {};
class CallsEvalField: public BitField<bool, 3, 1> {};
class LanguageModeField: public BitField<LanguageMode, 4, 2> {};
class FunctionVariableField: public BitField<FunctionVariableInfo, 6, 2> {};
diff --git a/src/parser.cc b/src/parser.cc
index f032d97..4aaa9a1 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -202,9 +202,8 @@
}
-void RegExpBuilder::AddQuantifierToAtom(int min,
- int max,
- RegExpQuantifier::Type type) {
+void RegExpBuilder::AddQuantifierToAtom(
+ int min, int max, RegExpQuantifier::QuantifierType quantifier_type) {
if (pending_empty_) {
pending_empty_ = false;
return;
@@ -244,7 +243,8 @@
UNREACHABLE();
return;
}
- terms_.Add(new(zone()) RegExpQuantifier(min, max, type, atom), zone());
+ terms_.Add(
+ new(zone()) RegExpQuantifier(min, max, quantifier_type, atom), zone());
LAST(ADD_TERM);
}
@@ -410,8 +410,8 @@
}
-Scope* Parser::NewScope(Scope* parent, ScopeType type) {
- Scope* result = new(zone()) Scope(parent, type, zone());
+Scope* Parser::NewScope(Scope* parent, ScopeType scope_type) {
+ Scope* result = new(zone()) Scope(parent, scope_type, zone());
result->Initialize();
return result;
}
@@ -758,7 +758,7 @@
info()->is_extended_mode());
ASSERT(info()->language_mode() == shared_info->language_mode());
scope->SetLanguageMode(shared_info->language_mode());
- FunctionLiteral::Type type = shared_info->is_expression()
+ FunctionLiteral::FunctionType function_type = shared_info->is_expression()
? (shared_info->is_anonymous()
? FunctionLiteral::ANONYMOUS_EXPRESSION
: FunctionLiteral::NAMED_EXPRESSION)
@@ -768,7 +768,7 @@
false, // Strict mode name already checked.
shared_info->is_generator(),
RelocInfo::kNoPosition,
- type,
+ function_type,
&ok);
// Make sure the results agree.
ASSERT(ok == (result != NULL));
@@ -799,20 +799,20 @@
}
-void Parser::ReportMessage(const char* type, Vector<const char*> args) {
+void Parser::ReportMessage(const char* message, Vector<const char*> args) {
Scanner::Location source_location = scanner().location();
- ReportMessageAt(source_location, type, args);
+ ReportMessageAt(source_location, message, args);
}
-void Parser::ReportMessage(const char* type, Vector<Handle<String> > args) {
+void Parser::ReportMessage(const char* message, Vector<Handle<String> > args) {
Scanner::Location source_location = scanner().location();
- ReportMessageAt(source_location, type, args);
+ ReportMessageAt(source_location, message, args);
}
void Parser::ReportMessageAt(Scanner::Location source_location,
- const char* type,
+ const char* message,
Vector<const char*> args) {
MessageLocation location(script_,
source_location.beg_pos,
@@ -824,13 +824,13 @@
elements->set(i, *arg_string);
}
Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
- Handle<Object> result = factory->NewSyntaxError(type, array);
+ Handle<Object> result = factory->NewSyntaxError(message, array);
isolate()->Throw(*result, &location);
}
void Parser::ReportMessageAt(Scanner::Location source_location,
- const char* type,
+ const char* message,
Vector<Handle<String> > args) {
MessageLocation location(script_,
source_location.beg_pos,
@@ -841,7 +841,7 @@
elements->set(i, *args[i]);
}
Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
- Handle<Object> result = factory->NewSyntaxError(type, array);
+ Handle<Object> result = factory->NewSyntaxError(message, array);
isolate()->Throw(*result, &location);
}
@@ -1538,12 +1538,12 @@
*ok = false;
return;
}
- Handle<String> type_string =
+ Handle<String> message_string =
isolate()->factory()->NewStringFromUtf8(CStrVector("Variable"),
TENURED);
Expression* expression =
NewThrowTypeError(isolate()->factory()->redeclaration_string(),
- type_string, name);
+ message_string, name);
declaration_scope->SetIllegalRedeclaration(expression);
}
}
@@ -2345,8 +2345,9 @@
Scope* declaration_scope = top_scope_->DeclarationScope();
if (declaration_scope->is_global_scope() ||
declaration_scope->is_eval_scope()) {
- Handle<String> type = isolate()->factory()->illegal_return_string();
- Expression* throw_error = NewThrowSyntaxError(type, Handle<Object>::null());
+ Handle<String> message = isolate()->factory()->illegal_return_string();
+ Expression* throw_error =
+ NewThrowSyntaxError(message, Handle<Object>::null());
return factory()->NewExpressionStatement(throw_error);
}
return result;
@@ -2737,9 +2738,9 @@
// error here but for compatibility with JSC we choose to report
// the error at runtime.
if (expression == NULL || !expression->IsValidLeftHandSide()) {
- Handle<String> type =
+ Handle<String> message =
isolate()->factory()->invalid_lhs_in_for_in_string();
- expression = NewThrowReferenceError(type);
+ expression = NewThrowReferenceError(message);
}
ForInStatement* loop = factory()->NewForInStatement(labels);
Target target(&this->target_stack_, loop);
@@ -2856,9 +2857,9 @@
// runtime.
// TODO(ES5): Should change parsing for spec conformance.
if (expression == NULL || !expression->IsValidLeftHandSide()) {
- Handle<String> type =
+ Handle<String> message =
isolate()->factory()->invalid_lhs_in_assignment_string();
- expression = NewThrowReferenceError(type);
+ expression = NewThrowReferenceError(message);
}
if (!top_scope_->is_classic_mode()) {
@@ -3126,9 +3127,9 @@
// error here but for compatibility with JSC we choose to report the
// error at runtime.
if (expression == NULL || !expression->IsValidLeftHandSide()) {
- Handle<String> type =
+ Handle<String> message =
isolate()->factory()->invalid_lhs_in_prefix_op_string();
- expression = NewThrowReferenceError(type);
+ expression = NewThrowReferenceError(message);
}
if (!top_scope_->is_classic_mode()) {
@@ -3161,9 +3162,9 @@
// error here but for compatibility with JSC we choose to report the
// error at runtime.
if (expression == NULL || !expression->IsValidLeftHandSide()) {
- Handle<String> type =
+ Handle<String> message =
isolate()->factory()->invalid_lhs_in_postfix_op_string();
- expression = NewThrowReferenceError(type);
+ expression = NewThrowReferenceError(message);
}
if (!top_scope_->is_classic_mode()) {
@@ -3322,14 +3323,14 @@
name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved_name,
CHECK_OK);
}
- FunctionLiteral::Type type = name.is_null()
+ FunctionLiteral::FunctionType function_type = name.is_null()
? FunctionLiteral::ANONYMOUS_EXPRESSION
: FunctionLiteral::NAMED_EXPRESSION;
result = ParseFunctionLiteral(name,
is_strict_reserved_name,
is_generator,
function_token_position,
- type,
+ function_type,
CHECK_OK);
} else {
result = ParsePrimaryExpression(CHECK_OK);
@@ -3658,24 +3659,25 @@
if (object_literal != NULL) {
ASSERT(object_literal->is_simple());
if (object_literal->fast_elements()) {
- result->set(kTypeSlot, Smi::FromInt(OBJECT_LITERAL_FAST_ELEMENTS));
+ result->set(kLiteralTypeSlot, Smi::FromInt(OBJECT_LITERAL_FAST_ELEMENTS));
} else {
- result->set(kTypeSlot, Smi::FromInt(OBJECT_LITERAL_SLOW_ELEMENTS));
+ result->set(kLiteralTypeSlot, Smi::FromInt(OBJECT_LITERAL_SLOW_ELEMENTS));
}
result->set(kElementsSlot, *object_literal->constant_properties());
} else {
ArrayLiteral* array_literal = expression->AsArrayLiteral();
ASSERT(array_literal != NULL && array_literal->is_simple());
- result->set(kTypeSlot, Smi::FromInt(ARRAY_LITERAL));
+ result->set(kLiteralTypeSlot, Smi::FromInt(ARRAY_LITERAL));
result->set(kElementsSlot, *array_literal->constant_elements());
}
return result;
}
-CompileTimeValue::Type CompileTimeValue::GetType(Handle<FixedArray> value) {
- Smi* type_value = Smi::cast(value->get(kTypeSlot));
- return static_cast<Type>(type_value->value());
+CompileTimeValue::LiteralType CompileTimeValue::GetLiteralType(
+ Handle<FixedArray> value) {
+ Smi* literal_type = Smi::cast(value->get(kLiteralTypeSlot));
+ return static_cast<LiteralType>(literal_type->value());
}
@@ -4163,12 +4165,13 @@
};
-FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
- bool name_is_strict_reserved,
- bool is_generator,
- int function_token_position,
- FunctionLiteral::Type type,
- bool* ok) {
+FunctionLiteral* Parser::ParseFunctionLiteral(
+ Handle<String> function_name,
+ bool name_is_strict_reserved,
+ bool is_generator,
+ int function_token_position,
+ FunctionLiteral::FunctionType function_type,
+ bool* ok) {
// Function ::
// '(' FormalParameterList? ')' '{' FunctionBody '}'
@@ -4186,7 +4189,8 @@
// Function declarations are function scoped in normal mode, so they are
// hoisted. In harmony block scoping mode they are block scoped, so they
// are not hoisted.
- Scope* scope = (type == FunctionLiteral::DECLARATION && !is_extended_mode())
+ Scope* scope =
+ (function_type == FunctionLiteral::DECLARATION && !is_extended_mode())
? NewScope(top_scope_->DeclarationScope(), FUNCTION_SCOPE)
: NewScope(top_scope_, FUNCTION_SCOPE);
ZoneList<Statement*>* body = NULL;
@@ -4272,7 +4276,7 @@
// instead of Variables and Proxis as is the case now.
Variable* fvar = NULL;
Token::Value fvar_init_op = Token::INIT_CONST;
- if (type == FunctionLiteral::NAMED_EXPRESSION) {
+ if (function_type == FunctionLiteral::NAMED_EXPRESSION) {
if (is_extended_mode()) fvar_init_op = Token::INIT_CONST_HARMONY;
VariableMode fvar_mode = is_extended_mode() ? CONST_HARMONY : CONST;
fvar = new(zone()) Variable(top_scope_,
@@ -4476,7 +4480,7 @@
handler_count,
num_parameters,
duplicate_parameters,
- type,
+ function_type,
FunctionLiteral::kIsFunction,
parenthesized,
generator);
@@ -4822,22 +4826,22 @@
}
-Expression* Parser::NewThrowReferenceError(Handle<String> type) {
+Expression* Parser::NewThrowReferenceError(Handle<String> message) {
return NewThrowError(isolate()->factory()->MakeReferenceError_string(),
- type, HandleVector<Object>(NULL, 0));
+ message, HandleVector<Object>(NULL, 0));
}
-Expression* Parser::NewThrowSyntaxError(Handle<String> type,
+Expression* Parser::NewThrowSyntaxError(Handle<String> message,
Handle<Object> first) {
int argc = first.is_null() ? 0 : 1;
Vector< Handle<Object> > arguments = HandleVector<Object>(&first, argc);
return NewThrowError(
- isolate()->factory()->MakeSyntaxError_string(), type, arguments);
+ isolate()->factory()->MakeSyntaxError_string(), message, arguments);
}
-Expression* Parser::NewThrowTypeError(Handle<String> type,
+Expression* Parser::NewThrowTypeError(Handle<String> message,
Handle<Object> first,
Handle<Object> second) {
ASSERT(!first.is_null() && !second.is_null());
@@ -4845,12 +4849,12 @@
Vector< Handle<Object> > arguments =
HandleVector<Object>(elements, ARRAY_SIZE(elements));
return NewThrowError(
- isolate()->factory()->MakeTypeError_string(), type, arguments);
+ isolate()->factory()->MakeTypeError_string(), message, arguments);
}
Expression* Parser::NewThrowError(Handle<String> constructor,
- Handle<String> type,
+ Handle<String> message,
Vector< Handle<Object> > arguments) {
int argc = arguments.length();
Handle<FixedArray> elements = isolate()->factory()->NewFixedArray(argc,
@@ -4865,7 +4869,7 @@
elements, FAST_ELEMENTS, TENURED);
ZoneList<Expression*>* args = new(zone()) ZoneList<Expression*>(2, zone());
- args->Add(factory()->NewLiteral(type), zone());
+ args->Add(factory()->NewLiteral(message), zone());
args->Add(factory()->NewLiteral(array), zone());
CallRuntime* call_constructor =
factory()->NewCallRuntime(constructor, NULL, args);
@@ -5006,20 +5010,21 @@
int end_capture_index = captures_started();
int capture_index = stored_state->capture_index();
- SubexpressionType type = stored_state->group_type();
+ SubexpressionType group_type = stored_state->group_type();
// Restore previous state.
stored_state = stored_state->previous_state();
builder = stored_state->builder();
// Build result of subexpression.
- if (type == CAPTURE) {
+ if (group_type == CAPTURE) {
RegExpCapture* capture = new(zone()) RegExpCapture(body, capture_index);
captures_->at(capture_index - 1) = capture;
body = capture;
- } else if (type != GROUPING) {
- ASSERT(type == POSITIVE_LOOKAHEAD || type == NEGATIVE_LOOKAHEAD);
- bool is_positive = (type == POSITIVE_LOOKAHEAD);
+ } else if (group_type != GROUPING) {
+ ASSERT(group_type == POSITIVE_LOOKAHEAD ||
+ group_type == NEGATIVE_LOOKAHEAD);
+ bool is_positive = (group_type == POSITIVE_LOOKAHEAD);
body = new(zone()) RegExpLookahead(body,
is_positive,
end_capture_index - capture_index,
@@ -5053,10 +5058,10 @@
}
case '$': {
Advance();
- RegExpAssertion::Type type =
+ RegExpAssertion::AssertionType assertion_type =
multiline_ ? RegExpAssertion::END_OF_LINE :
RegExpAssertion::END_OF_INPUT;
- builder->AddAssertion(new(zone()) RegExpAssertion(type));
+ builder->AddAssertion(new(zone()) RegExpAssertion(assertion_type));
continue;
}
case '.': {
@@ -5070,18 +5075,18 @@
break;
}
case '(': {
- SubexpressionType type = CAPTURE;
+ SubexpressionType subexpr_type = CAPTURE;
Advance();
if (current() == '?') {
switch (Next()) {
case ':':
- type = GROUPING;
+ subexpr_type = GROUPING;
break;
case '=':
- type = POSITIVE_LOOKAHEAD;
+ subexpr_type = POSITIVE_LOOKAHEAD;
break;
case '!':
- type = NEGATIVE_LOOKAHEAD;
+ subexpr_type = NEGATIVE_LOOKAHEAD;
break;
default:
ReportError(CStrVector("Invalid group") CHECK_FAILED);
@@ -5098,7 +5103,7 @@
captures_->Add(NULL, zone());
}
// Store current state and begin new disjunction parsing.
- stored_state = new(zone()) RegExpParserState(stored_state, type,
+ stored_state = new(zone()) RegExpParserState(stored_state, subexpr_type,
captures_started(), zone());
builder = stored_state->builder();
continue;
@@ -5286,16 +5291,16 @@
default:
continue;
}
- RegExpQuantifier::Type type = RegExpQuantifier::GREEDY;
+ RegExpQuantifier::QuantifierType quantifier_type = RegExpQuantifier::GREEDY;
if (current() == '?') {
- type = RegExpQuantifier::NON_GREEDY;
+ quantifier_type = RegExpQuantifier::NON_GREEDY;
Advance();
} else if (FLAG_regexp_possessive_quantifier && current() == '+') {
// FLAG_regexp_possessive_quantifier is a debug-only flag.
- type = RegExpQuantifier::POSSESSIVE;
+ quantifier_type = RegExpQuantifier::POSSESSIVE;
Advance();
}
- builder->AddQuantifierToAtom(min, max, type);
+ builder->AddQuantifierToAtom(min, max, quantifier_type);
}
}
diff --git a/src/parser.h b/src/parser.h
index ed9ee10..eea617f 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -269,7 +269,8 @@
void AddAtom(RegExpTree* tree);
void AddAssertion(RegExpTree* tree);
void NewAlternative(); // '|'
- void AddQuantifierToAtom(int min, int max, RegExpQuantifier::Type type);
+ void AddQuantifierToAtom(
+ int min, int max, RegExpQuantifier::QuantifierType type);
RegExpTree* ToRegExp();
private:
@@ -690,7 +691,7 @@
bool name_is_reserved,
bool is_generator,
int function_token_position,
- FunctionLiteral::Type type,
+ FunctionLiteral::FunctionType type,
bool* ok);
@@ -867,7 +868,7 @@
// can be fully handled at compile time.
class CompileTimeValue: public AllStatic {
public:
- enum Type {
+ enum LiteralType {
OBJECT_LITERAL_FAST_ELEMENTS,
OBJECT_LITERAL_SLOW_ELEMENTS,
ARRAY_LITERAL
@@ -881,13 +882,13 @@
static Handle<FixedArray> GetValue(Expression* expression);
// Get the type of a compile time value returned by GetValue().
- static Type GetType(Handle<FixedArray> value);
+ static LiteralType GetLiteralType(Handle<FixedArray> value);
// Get the elements array of a compile time value returned by GetValue().
static Handle<FixedArray> GetElements(Handle<FixedArray> value);
private:
- static const int kTypeSlot = 0;
+ static const int kLiteralTypeSlot = 0;
static const int kElementsSlot = 1;
DISALLOW_IMPLICIT_CONSTRUCTORS(CompileTimeValue);
diff --git a/src/regexp-macro-assembler-irregexp.cc b/src/regexp-macro-assembler-irregexp.cc
index e678d60..c69011f 100644
--- a/src/regexp-macro-assembler-irregexp.cc
+++ b/src/regexp-macro-assembler-irregexp.cc
@@ -410,28 +410,6 @@
}
-void RegExpMacroAssemblerIrregexp::CheckCharacters(
- Vector<const uc16> str,
- int cp_offset,
- Label* on_failure,
- bool check_end_of_string) {
- ASSERT(cp_offset >= kMinCPOffset);
- ASSERT(cp_offset + str.length() - 1 <= kMaxCPOffset);
- // It is vital that this loop is backwards due to the unchecked character
- // load below.
- for (int i = str.length() - 1; i >= 0; i--) {
- if (check_end_of_string && i == str.length() - 1) {
- Emit(BC_LOAD_CURRENT_CHAR, cp_offset + i);
- EmitOrLink(on_failure);
- } else {
- Emit(BC_LOAD_CURRENT_CHAR_UNCHECKED, cp_offset + i);
- }
- Emit(BC_CHECK_NOT_CHAR, str[i]);
- EmitOrLink(on_failure);
- }
-}
-
-
void RegExpMacroAssemblerIrregexp::IfRegisterLT(int register_index,
int comparand,
Label* on_less_than) {
diff --git a/src/regexp-macro-assembler-irregexp.h b/src/regexp-macro-assembler-irregexp.h
index 4bc2980..3569d8b 100644
--- a/src/regexp-macro-assembler-irregexp.h
+++ b/src/regexp-macro-assembler-irregexp.h
@@ -103,10 +103,6 @@
virtual void CheckNotBackReference(int start_reg, Label* on_no_match);
virtual void CheckNotBackReferenceIgnoreCase(int start_reg,
Label* on_no_match);
- virtual void CheckCharacters(Vector<const uc16> str,
- int cp_offset,
- Label* on_failure,
- bool check_end_of_string);
virtual void IfRegisterLT(int register_index, int comparand, Label* if_lt);
virtual void IfRegisterGE(int register_index, int comparand, Label* if_ge);
virtual void IfRegisterEqPos(int register_index, Label* if_eq);
diff --git a/src/regexp-macro-assembler-tracer.cc b/src/regexp-macro-assembler-tracer.cc
index f878e8c..1ce1fa4 100644
--- a/src/regexp-macro-assembler-tracer.cc
+++ b/src/regexp-macro-assembler-tracer.cc
@@ -383,21 +383,6 @@
}
-void RegExpMacroAssemblerTracer::CheckCharacters(Vector<const uc16> str,
- int cp_offset,
- Label* on_failure,
- bool check_end_of_string) {
- PrintF(" %s(str=\"",
- check_end_of_string ? "CheckCharacters" : "CheckCharactersUnchecked");
- for (int i = 0; i < str.length(); i++) {
- PrintF("0x%04x", str[i]);
- }
- PrintF("\", cp_offset=%d, label[%08x])\n",
- cp_offset, LabelToInt(on_failure));
- assembler_->CheckCharacters(str, cp_offset, on_failure, check_end_of_string);
-}
-
-
bool RegExpMacroAssemblerTracer::CheckSpecialCharacterClass(
uc16 type,
Label* on_no_match) {
diff --git a/src/regexp-macro-assembler-tracer.h b/src/regexp-macro-assembler-tracer.h
index ac262df..852fb80 100644
--- a/src/regexp-macro-assembler-tracer.h
+++ b/src/regexp-macro-assembler-tracer.h
@@ -49,11 +49,6 @@
Label* on_equal);
virtual void CheckCharacterGT(uc16 limit, Label* on_greater);
virtual void CheckCharacterLT(uc16 limit, Label* on_less);
- virtual void CheckCharacters(
- Vector<const uc16> str,
- int cp_offset,
- Label* on_failure,
- bool check_end_of_string);
virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
virtual void CheckNotAtStart(Label* on_not_at_start);
virtual void CheckNotBackReference(int start_reg, Label* on_no_match);
diff --git a/src/regexp-macro-assembler.h b/src/regexp-macro-assembler.h
index 211ab6b..1ff8bd9 100644
--- a/src/regexp-macro-assembler.h
+++ b/src/regexp-macro-assembler.h
@@ -87,17 +87,6 @@
Label* on_equal) = 0;
virtual void CheckCharacterGT(uc16 limit, Label* on_greater) = 0;
virtual void CheckCharacterLT(uc16 limit, Label* on_less) = 0;
- // Check the current character for a match with a literal string. If we
- // fail to match then goto the on_failure label. If check_eos is set then
- // the end of input always fails. If check_eos is clear then it is the
- // caller's responsibility to ensure that the end of string is not hit.
- // If the label is NULL then we should pop a backtrack address off
- // the stack and go to that.
- virtual void CheckCharacters(
- Vector<const uc16> str,
- int cp_offset,
- Label* on_failure,
- bool check_eos) = 0;
virtual void CheckGreedyLoop(Label* on_tos_equals_current_position) = 0;
virtual void CheckNotAtStart(Label* on_not_at_start) = 0;
virtual void CheckNotBackReference(int start_reg, Label* on_no_match) = 0;
diff --git a/src/runtime.cc b/src/runtime.cc
index f8147a2..0516c9c 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -425,7 +425,7 @@
Handle<FixedArray> array) {
Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
const bool kHasNoFunctionLiteral = false;
- switch (CompileTimeValue::GetType(array)) {
+ switch (CompileTimeValue::GetLiteralType(array)) {
case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
return CreateObjectLiteralBoilerplate(isolate,
literals,
@@ -11234,7 +11234,9 @@
context_ = Handle<Context>(context_->previous(), isolate_);
}
}
- if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
+ if (scope_info->scope_type() != EVAL_SCOPE) {
+ nested_scope_chain_.Add(scope_info);
+ }
} else {
// Reparse the code and analyze the scopes.
Handle<Script> script(Script::cast(shared_info->script()));
@@ -11242,13 +11244,13 @@
// Check whether we are in global, eval or function code.
Handle<ScopeInfo> scope_info(shared_info->scope_info());
- if (scope_info->Type() != FUNCTION_SCOPE) {
+ if (scope_info->scope_type() != FUNCTION_SCOPE) {
// Global or eval code.
CompilationInfoWithZone info(script);
- if (scope_info->Type() == GLOBAL_SCOPE) {
+ if (scope_info->scope_type() == GLOBAL_SCOPE) {
info.MarkAsGlobal();
} else {
- ASSERT(scope_info->Type() == EVAL_SCOPE);
+ ASSERT(scope_info->scope_type() == EVAL_SCOPE);
info.MarkAsEval();
info.SetContext(Handle<Context>(function_->context()));
}
@@ -11314,7 +11316,7 @@
ASSERT(!failed_);
if (!nested_scope_chain_.is_empty()) {
Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
- switch (scope_info->Type()) {
+ switch (scope_info->scope_type()) {
case FUNCTION_SCOPE:
ASSERT(context_->IsFunctionContext() ||
!scope_info->HasContext());
@@ -12022,7 +12024,7 @@
Handle<Context> current = context_chain.RemoveLast();
ASSERT(!(scope_info->HasContext() & current.is_null()));
- if (scope_info->Type() == CATCH_SCOPE) {
+ if (scope_info->scope_type() == CATCH_SCOPE) {
ASSERT(current->IsCatchContext());
Handle<String> name(String::cast(current->extension()));
Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX),
@@ -12032,7 +12034,7 @@
context,
name,
thrown_object);
- } else if (scope_info->Type() == BLOCK_SCOPE) {
+ } else if (scope_info->scope_type() == BLOCK_SCOPE) {
// Materialize the contents of the block scope into a JSObject.
ASSERT(current->IsBlockContext());
Handle<JSObject> block_scope_object =
@@ -12047,7 +12049,7 @@
new_context->set_previous(*context);
context = new_context;
} else {
- ASSERT(scope_info->Type() == WITH_SCOPE);
+ ASSERT(scope_info->scope_type() == WITH_SCOPE);
ASSERT(current->IsWithContext());
Handle<JSObject> extension(JSObject::cast(current->extension()));
context =
@@ -13441,6 +13443,107 @@
}
+static MaybeObject* ArrayConstructorCommon(Isolate* isolate,
+ Handle<JSFunction> constructor,
+ Handle<Object> type_info,
+ Arguments* caller_args) {
+ bool holey = false;
+ bool can_use_type_feedback = true;
+ if (caller_args->length() == 1) {
+ Object* argument_one = (*caller_args)[0];
+ if (argument_one->IsSmi()) {
+ int value = Smi::cast(argument_one)->value();
+ if (value < 0 || value >= JSObject::kInitialMaxFastElementArray) {
+ // the array is a dictionary in this case.
+ can_use_type_feedback = false;
+ } else if (value != 0) {
+ holey = true;
+ }
+ } else {
+ // Non-smi length argument produces a dictionary
+ can_use_type_feedback = false;
+ }
+ }
+
+ JSArray* array;
+ MaybeObject* maybe_array;
+ if (!type_info.is_null() &&
+ *type_info != isolate->heap()->undefined_value() &&
+ JSGlobalPropertyCell::cast(*type_info)->value()->IsSmi() &&
+ can_use_type_feedback) {
+ JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(*type_info);
+ Smi* smi = Smi::cast(cell->value());
+ ElementsKind to_kind = static_cast<ElementsKind>(smi->value());
+ if (holey && !IsFastHoleyElementsKind(to_kind)) {
+ to_kind = GetHoleyElementsKind(to_kind);
+ // Update the allocation site info to reflect the advice alteration.
+ cell->set_value(Smi::FromInt(to_kind));
+ }
+
+ maybe_array = isolate->heap()->AllocateJSObjectWithAllocationSite(
+ *constructor, type_info);
+ if (!maybe_array->To(&array)) return maybe_array;
+ } else {
+ maybe_array = isolate->heap()->AllocateJSObject(*constructor);
+ if (!maybe_array->To(&array)) return maybe_array;
+ // We might need to transition to holey
+ ElementsKind kind = constructor->initial_map()->elements_kind();
+ if (holey && !IsFastHoleyElementsKind(kind)) {
+ kind = GetHoleyElementsKind(kind);
+ maybe_array = array->TransitionElementsKind(kind);
+ if (maybe_array->IsFailure()) return maybe_array;
+ }
+ }
+
+ maybe_array = isolate->heap()->AllocateJSArrayStorage(array, 0, 0,
+ DONT_INITIALIZE_ARRAY_ELEMENTS);
+ if (maybe_array->IsFailure()) return maybe_array;
+ maybe_array = ArrayConstructInitializeElements(array, caller_args);
+ if (maybe_array->IsFailure()) return maybe_array;
+ return array;
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConstructor) {
+ HandleScope scope(isolate);
+ // If we get 2 arguments then they are the stub parameters (constructor, type
+ // info). If we get 3, then the first one is a pointer to the arguments
+ // passed by the caller.
+ Arguments empty_args(0, NULL);
+ bool no_caller_args = args.length() == 2;
+ ASSERT(no_caller_args || args.length() == 3);
+ int parameters_start = no_caller_args ? 0 : 1;
+ Arguments* caller_args = no_caller_args
+ ? &empty_args
+ : reinterpret_cast<Arguments*>(args[0]);
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
+ CONVERT_ARG_HANDLE_CHECKED(Object, type_info, parameters_start + 1);
+
+ return ArrayConstructorCommon(isolate,
+ constructor,
+ type_info,
+ caller_args);
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalArrayConstructor) {
+ HandleScope scope(isolate);
+ Arguments empty_args(0, NULL);
+ bool no_caller_args = args.length() == 1;
+ ASSERT(no_caller_args || args.length() == 2);
+ int parameters_start = no_caller_args ? 0 : 1;
+ Arguments* caller_args = no_caller_args
+ ? &empty_args
+ : reinterpret_cast<Arguments*>(args[0]);
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
+
+ return ArrayConstructorCommon(isolate,
+ constructor,
+ Handle<Object>::null(),
+ caller_args);
+}
+
+
// ----------------------------------------------------------------------------
// Implementation of Runtime
diff --git a/src/runtime.h b/src/runtime.h
index 73177ea..c28972c 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -287,6 +287,8 @@
F(GetArrayKeys, 2, 1) \
F(MoveArrayContents, 2, 1) \
F(EstimateNumberOfElements, 1, 1) \
+ F(ArrayConstructor, -1, 1) \
+ F(InternalArrayConstructor, -1, 1) \
\
/* Getters and Setters */ \
F(LookupAccessor, 3, 1) \
diff --git a/src/scopeinfo.cc b/src/scopeinfo.cc
index b9dea22..c9df1fb 100644
--- a/src/scopeinfo.cc
+++ b/src/scopeinfo.cc
@@ -78,7 +78,7 @@
Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
// Encode the flags.
- int flags = TypeField::encode(scope->type()) |
+ int flags = ScopeTypeField::encode(scope->scope_type()) |
CallsEvalField::encode(scope->calls_eval()) |
LanguageModeField::encode(scope->language_mode()) |
FunctionVariableField::encode(function_name_info) |
@@ -155,9 +155,9 @@
}
-ScopeType ScopeInfo::Type() {
+ScopeType ScopeInfo::scope_type() {
ASSERT(length() > 0);
- return TypeField::decode(Flags());
+ return ScopeTypeField::decode(Flags());
}
@@ -193,9 +193,9 @@
FunctionVariableField::decode(Flags()) == CONTEXT;
bool has_context = context_locals > 0 ||
function_name_context_slot ||
- Type() == WITH_SCOPE ||
- (Type() == FUNCTION_SCOPE && CallsEval()) ||
- Type() == MODULE_SCOPE;
+ scope_type() == WITH_SCOPE ||
+ (scope_type() == FUNCTION_SCOPE && CallsEval()) ||
+ scope_type() == MODULE_SCOPE;
if (has_context) {
return Context::MIN_CONTEXT_SLOTS + context_locals +
(function_name_context_slot ? 1 : 0);
diff --git a/src/scopes.cc b/src/scopes.cc
index 208dc76..6ae7cc0 100644
--- a/src/scopes.cc
+++ b/src/scopes.cc
@@ -104,7 +104,7 @@
// ----------------------------------------------------------------------------
// Implementation of Scope
-Scope::Scope(Scope* outer_scope, ScopeType type, Zone* zone)
+Scope::Scope(Scope* outer_scope, ScopeType scope_type, Zone* zone)
: isolate_(zone->isolate()),
inner_scopes_(4, zone),
variables_(zone),
@@ -114,19 +114,19 @@
unresolved_(16, zone),
decls_(4, zone),
interface_(FLAG_harmony_modules &&
- (type == MODULE_SCOPE || type == GLOBAL_SCOPE)
+ (scope_type == MODULE_SCOPE || scope_type == GLOBAL_SCOPE)
? Interface::NewModule(zone) : NULL),
already_resolved_(false),
zone_(zone) {
- SetDefaults(type, outer_scope, Handle<ScopeInfo>::null());
+ SetDefaults(scope_type, outer_scope, Handle<ScopeInfo>::null());
// The outermost scope must be a global scope.
- ASSERT(type == GLOBAL_SCOPE || outer_scope != NULL);
+ ASSERT(scope_type == GLOBAL_SCOPE || outer_scope != NULL);
ASSERT(!HasIllegalRedeclaration());
}
Scope::Scope(Scope* inner_scope,
- ScopeType type,
+ ScopeType scope_type,
Handle<ScopeInfo> scope_info,
Zone* zone)
: isolate_(Isolate::Current()),
@@ -140,7 +140,7 @@
interface_(NULL),
already_resolved_(true),
zone_(zone) {
- SetDefaults(type, NULL, scope_info);
+ SetDefaults(scope_type, NULL, scope_info);
if (!scope_info.is_null()) {
num_heap_slots_ = scope_info_->ContextLength();
}
@@ -177,11 +177,11 @@
}
-void Scope::SetDefaults(ScopeType type,
+void Scope::SetDefaults(ScopeType scope_type,
Scope* outer_scope,
Handle<ScopeInfo> scope_info) {
outer_scope_ = outer_scope;
- type_ = type;
+ scope_type_ = scope_type;
scope_name_ = isolate_->factory()->empty_string();
dynamics_ = NULL;
receiver_ = NULL;
@@ -780,8 +780,8 @@
#ifdef DEBUG
-static const char* Header(ScopeType type) {
- switch (type) {
+static const char* Header(ScopeType scope_type) {
+ switch (scope_type) {
case EVAL_SCOPE: return "eval";
case FUNCTION_SCOPE: return "function";
case MODULE_SCOPE: return "module";
@@ -855,7 +855,7 @@
int n1 = n0 + 2; // indentation
// Print header.
- Indent(n0, Header(type_));
+ Indent(n0, Header(scope_type_));
if (scope_name_->length() > 0) {
PrintF(" ");
PrintName(scope_name_);
diff --git a/src/scopes.h b/src/scopes.h
index 66384a1..06aaa90 100644
--- a/src/scopes.h
+++ b/src/scopes.h
@@ -97,7 +97,7 @@
// ---------------------------------------------------------------------------
// Construction
- Scope(Scope* outer_scope, ScopeType type, Zone* zone);
+ Scope(Scope* outer_scope, ScopeType scope_type, Zone* zone);
// Compute top scope and allocate variables. For lazy compilation the top
// scope only contains the single lazily compiled function, so this
@@ -282,13 +282,13 @@
// Predicates.
// Specific scope types.
- bool is_eval_scope() const { return type_ == EVAL_SCOPE; }
- bool is_function_scope() const { return type_ == FUNCTION_SCOPE; }
- bool is_module_scope() const { return type_ == MODULE_SCOPE; }
- bool is_global_scope() const { return type_ == GLOBAL_SCOPE; }
- bool is_catch_scope() const { return type_ == CATCH_SCOPE; }
- bool is_block_scope() const { return type_ == BLOCK_SCOPE; }
- bool is_with_scope() const { return type_ == WITH_SCOPE; }
+ bool is_eval_scope() const { return scope_type_ == EVAL_SCOPE; }
+ bool is_function_scope() const { return scope_type_ == FUNCTION_SCOPE; }
+ bool is_module_scope() const { return scope_type_ == MODULE_SCOPE; }
+ bool is_global_scope() const { return scope_type_ == GLOBAL_SCOPE; }
+ bool is_catch_scope() const { return scope_type_ == CATCH_SCOPE; }
+ bool is_block_scope() const { return scope_type_ == BLOCK_SCOPE; }
+ bool is_with_scope() const { return scope_type_ == WITH_SCOPE; }
bool is_declaration_scope() const {
return is_eval_scope() || is_function_scope() ||
is_module_scope() || is_global_scope();
@@ -321,7 +321,7 @@
// Accessors.
// The type of this scope.
- ScopeType type() const { return type_; }
+ ScopeType scope_type() const { return scope_type_; }
// The language mode of this scope.
LanguageMode language_mode() const { return language_mode_; }
@@ -449,7 +449,7 @@
ZoneList<Scope*> inner_scopes_; // the immediately enclosed inner scopes
// The scope type.
- ScopeType type_;
+ ScopeType scope_type_;
// Debugging support.
Handle<String> scope_name_;
diff --git a/src/typedarray.js b/src/typedarray.js
index 4fade00..04c487f 100644
--- a/src/typedarray.js
+++ b/src/typedarray.js
@@ -94,7 +94,7 @@
} else if (!IS_UNDEFINED(arg1)){
ConstructByArrayLike(this, arg1);
} else {
- throw MakeTypeError("parameterless_typed_array_constr", name);
+ throw MakeTypeError("parameterless_typed_array_constr", [name]);
}
} else {
return new constructor(arg1, arg2, arg3);
diff --git a/src/types.cc b/src/types.cc
new file mode 100644
index 0000000..2a96055
--- /dev/null
+++ b/src/types.cc
@@ -0,0 +1,281 @@
+// Copyright 2013 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 "types.h"
+
+namespace v8 {
+namespace internal {
+
+// Get the smallest bitset subsuming this type.
+int Type::LubBitset() {
+ if (this->is_bitset()) {
+ return this->as_bitset();
+ } else if (this->is_union()) {
+ Handle<Unioned> unioned = this->as_union();
+ int bitset = kNone;
+ for (int i = 0; i < unioned->length(); ++i) {
+ bitset |= union_get(unioned, i)->LubBitset();
+ }
+ return bitset;
+ } else {
+ Map* map =
+ this->is_class() ? *this->as_class() : this->as_constant()->map();
+ switch (map->instance_type()) {
+ case STRING_TYPE:
+ case ASCII_STRING_TYPE:
+ case CONS_STRING_TYPE:
+ case CONS_ASCII_STRING_TYPE:
+ case SLICED_STRING_TYPE:
+ case EXTERNAL_STRING_TYPE:
+ case EXTERNAL_ASCII_STRING_TYPE:
+ case EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE:
+ case SHORT_EXTERNAL_STRING_TYPE:
+ case SHORT_EXTERNAL_ASCII_STRING_TYPE:
+ case SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE:
+ case INTERNALIZED_STRING_TYPE:
+ case ASCII_INTERNALIZED_STRING_TYPE:
+ case CONS_INTERNALIZED_STRING_TYPE:
+ case CONS_ASCII_INTERNALIZED_STRING_TYPE:
+ case EXTERNAL_INTERNALIZED_STRING_TYPE:
+ case EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE:
+ case EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE:
+ case SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE:
+ case SHORT_EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE:
+ case SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE:
+ return kString;
+ case SYMBOL_TYPE:
+ return kSymbol;
+ case ODDBALL_TYPE:
+ return kOddball;
+ case HEAP_NUMBER_TYPE:
+ return kDouble;
+ case JS_VALUE_TYPE:
+ case JS_DATE_TYPE:
+ case JS_OBJECT_TYPE:
+ case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
+ case JS_GENERATOR_OBJECT_TYPE:
+ case JS_MODULE_TYPE:
+ case JS_GLOBAL_OBJECT_TYPE:
+ case JS_BUILTINS_OBJECT_TYPE:
+ case JS_GLOBAL_PROXY_TYPE:
+ case JS_ARRAY_BUFFER_TYPE:
+ case JS_TYPED_ARRAY_TYPE:
+ case JS_WEAK_MAP_TYPE:
+ case JS_REGEXP_TYPE:
+ return kOtherObject;
+ case JS_ARRAY_TYPE:
+ return kArray;
+ case JS_FUNCTION_TYPE:
+ return kFunction;
+ case JS_PROXY_TYPE:
+ case JS_FUNCTION_PROXY_TYPE:
+ return kProxy;
+ default:
+ UNREACHABLE();
+ return kNone;
+ }
+ }
+}
+
+
+// Get the largest bitset subsumed by this type.
+int Type::GlbBitset() {
+ if (this->is_bitset()) {
+ return this->as_bitset();
+ } else if (this->is_union()) {
+ // All but the first are non-bitsets and thus would yield kNone anyway.
+ return union_get(this->as_union(), 0)->GlbBitset();
+ } else {
+ return kNone;
+ }
+}
+
+
+// Check this <= that.
+bool Type::Is(Handle<Type> that) {
+ // Fast path for bitsets.
+ if (that->is_bitset()) {
+ return (this->LubBitset() | that->as_bitset()) == that->as_bitset();
+ }
+
+ if (that->is_class()) {
+ return this->is_class() && *this->as_class() == *that->as_class();
+ }
+ if (that->is_constant()) {
+ return this->is_constant() && *this->as_constant() == *that->as_constant();
+ }
+
+ // (T1 \/ ... \/ Tn) <= T <=> (T1 <= T) /\ ... /\ (Tn <= T)
+ if (this->is_union()) {
+ Handle<Unioned> unioned = this->as_union();
+ for (int i = 0; i < unioned->length(); ++i) {
+ Handle<Type> this_i = union_get(unioned, i);
+ if (!this_i->Is(that)) return false;
+ }
+ return true;
+ }
+
+ // T <= (T1 \/ ... \/ Tn) <=> (T <= T1) \/ ... \/ (T <= Tn)
+ // (iff T is not a union)
+ if (that->is_union()) {
+ Handle<Unioned> unioned = that->as_union();
+ for (int i = 0; i < unioned->length(); ++i) {
+ Handle<Type> that_i = union_get(unioned, i);
+ if (this->Is(that_i)) return true;
+ if (this->is_bitset()) break; // Fast fail, no other field is a bitset.
+ }
+ return false;
+ }
+
+ return false;
+}
+
+
+// Check this overlaps that.
+bool Type::Maybe(Handle<Type> that) {
+ // Fast path for bitsets.
+ if (this->is_bitset()) {
+ return (this->as_bitset() & that->LubBitset()) != 0;
+ }
+ if (that->is_bitset()) {
+ return (this->LubBitset() & that->as_bitset()) != 0;
+ }
+
+ if (this->is_class()) {
+ return that->is_class() && *this->as_class() == *that->as_class();
+ }
+ if (this->is_constant()) {
+ return that->is_constant() && *this->as_constant() == *that->as_constant();
+ }
+
+ // (T1 \/ ... \/ Tn) overlaps T <=> (T1 overlaps T) \/ ... \/ (Tn overlaps T)
+ if (this->is_union()) {
+ Handle<Unioned> unioned = this->as_union();
+ for (int i = 0; i < unioned->length(); ++i) {
+ Handle<Type> this_i = union_get(unioned, i);
+ if (this_i->Maybe(that)) return true;
+ }
+ return false;
+ }
+
+ // T overlaps (T1 \/ ... \/ Tn) <=> (T overlaps T1) \/ ... \/ (T overlaps Tn)
+ if (that->is_union()) {
+ Handle<Unioned> unioned = that->as_union();
+ for (int i = 0; i < unioned->length(); ++i) {
+ Handle<Type> that_i = union_get(unioned, i);
+ if (this->Maybe(that_i)) return true;
+ }
+ return false;
+ }
+
+ return false;
+}
+
+
+bool Type::InUnion(Handle<Unioned> unioned, int current_size) {
+ ASSERT(!this->is_union());
+ for (int i = 0; i < current_size; ++i) {
+ Handle<Type> type = union_get(unioned, i);
+ if (type->is_bitset() ? this->Is(type) : this == *type) return true;
+ }
+ return false;
+}
+
+// Get non-bitsets from this which are not subsumed by that, store at unioned,
+// starting at index. Returns updated index.
+int Type::ExtendUnion(Handle<Unioned> result, int current_size) {
+ int old_size = current_size;
+ if (this->is_class() || this->is_constant()) {
+ if (!this->InUnion(result, old_size)) result->set(current_size++, this);
+ } else if (this->is_union()) {
+ Handle<Unioned> unioned = this->as_union();
+ for (int i = 0; i < unioned->length(); ++i) {
+ Handle<Type> type = union_get(unioned, i);
+ ASSERT(i == 0 || !(type->is_bitset() || type->Is(union_get(unioned, 0))));
+ if (type->is_bitset()) continue;
+ if (!type->InUnion(result, old_size)) result->set(current_size++, *type);
+ }
+ }
+ return current_size;
+}
+
+
+// Union is O(1) on simple bit unions, but O(n*m) on structured unions.
+// TODO(rossberg): Should we use object sets somehow? Is it worth it?
+Type* Type::Union(Handle<Type> type1, Handle<Type> type2) {
+ // Fast case: bit sets.
+ if (type1->is_bitset() && type2->is_bitset()) {
+ return from_bitset(type1->as_bitset() | type2->as_bitset());
+ }
+
+ // Semi-fast case: Unioned objects are neither involved nor produced.
+ if (!(type1->is_union() || type2->is_union())) {
+ if (type1->Is(type2)) return *type2;
+ if (type2->Is(type1)) return *type1;
+ }
+
+ // Slow case: may need to produce a Unioned object.
+ Isolate* isolate = NULL;
+ int size = type1->is_bitset() || type2->is_bitset() ? 1 : 0;
+ if (!type1->is_bitset()) {
+ isolate = HeapObject::cast(*type1)->GetIsolate();
+ size += (type1->is_union() ? type1->as_union()->length() : 1);
+ }
+ if (!type2->is_bitset()) {
+ isolate = HeapObject::cast(*type2)->GetIsolate();
+ size += (type2->is_union() ? type2->as_union()->length() : 1);
+ }
+ ASSERT(isolate != NULL);
+ ASSERT(size >= 2);
+ Handle<Unioned> unioned = isolate->factory()->NewFixedArray(size);
+ size = 0;
+
+ int bitset = type1->GlbBitset() | type2->GlbBitset();
+ if (bitset != kNone) unioned->set(size++, from_bitset(bitset));
+ size = type1->ExtendUnion(unioned, size);
+ size = type2->ExtendUnion(unioned, size);
+
+ if (size == 1) {
+ return *union_get(unioned, 0);
+ } else if (size == unioned->length()) {
+ return from_handle(unioned);
+ }
+
+ // There was an overlap. Copy to smaller union.
+ Handle<Unioned> result = isolate->factory()->NewFixedArray(size);
+ for (int i = 0; i < size; ++i) result->set(i, unioned->get(i));
+ return from_handle(result);
+}
+
+
+Type* Type::Optional(Handle<Type> type) {
+ return type->is_bitset()
+ ? from_bitset(type->as_bitset() | kUndefined)
+ : Union(type, Undefined()->handle_via_isolate_of(*type));
+}
+
+} } // namespace v8::internal
diff --git a/src/types.h b/src/types.h
new file mode 100644
index 0000000..018969f
--- /dev/null
+++ b/src/types.h
@@ -0,0 +1,200 @@
+// Copyright 2013 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_TYPES_H_
+#define V8_TYPES_H_
+
+#include "v8.h"
+
+#include "objects.h"
+
+namespace v8 {
+namespace internal {
+
+
+// A simple type system for compiler-internal use. It is based entirely on
+// union types, and all subtyping hence amounts to set inclusion. Besides the
+// obvious primitive types and some predefined unions, the type language also
+// can express class types (a.k.a. specific maps) and singleton types (i.e.,
+// concrete constants).
+//
+// The following equations and inequations hold:
+//
+// None <= T
+// T <= Any
+//
+// Oddball = Boolean \/ Null \/ Undefined
+// Number = Smi \/ Double
+// Name = String \/ Symbol
+// UniqueName = InternalizedString \/ Symbol
+// InternalizedString < String
+//
+// Receiver = Object \/ Proxy
+// Array < Object
+// Function < Object
+//
+// Class(map) < T iff instance_type(map) < T
+// Constant(x) < T iff instance_type(map(x)) < T
+//
+// Note that Constant(x) < Class(map(x)) does _not_ hold, since x's map can
+// change! (Its instance type cannot, however.)
+// TODO(rossberg): the latter is not currently true for proxies, because of fix,
+// but will hold once we implement direct proxies.
+//
+// There are two main functions for testing types:
+//
+// T1->Is(T2) -- tests whether T1 is included in T2 (i.e., T1 <= T2)
+// T1->Maybe(T2) -- tests whether T1 and T2 overlap (i.e., T1 /\ T2 =/= 0)
+//
+// Typically, the latter should be used to check whether a specific case needs
+// handling (e.g., via T->Maybe(Number)).
+//
+// There is no functionality to discover whether a type is a leaf in the
+// lattice. That is intentional. It should always be possible to refine the
+// lattice (e.g., splitting up number types further) without invalidating any
+// existing assumptions or tests.
+//
+// Internally, all 'primitive' types, and their unions, are represented as
+// bitsets via smis. Class and Constant are heap pointers to the respective
+// argument. Only unions containing Class'es or Constant's require allocation.
+//
+// The type representation is heap-allocated, so cannot (currently) be used in
+// a parallel compilation context.
+
+class Type : public Object {
+ public:
+ static Type* None() { return from_bitset(kNone); }
+ static Type* Any() { return from_bitset(kAny); }
+
+ static Type* Oddball() { return from_bitset(kOddball); }
+ static Type* Boolean() { return from_bitset(kBoolean); }
+ static Type* Null() { return from_bitset(kNull); }
+ static Type* Undefined() { return from_bitset(kUndefined); }
+
+ static Type* Number() { return from_bitset(kNumber); }
+ static Type* Smi() { return from_bitset(kSmi); }
+ static Type* Double() { return from_bitset(kDouble); }
+
+ static Type* Name() { return from_bitset(kName); }
+ static Type* UniqueName() { return from_bitset(kUniqueName); }
+ static Type* String() { return from_bitset(kString); }
+ static Type* InternalizedString() { return from_bitset(kInternalizedString); }
+ static Type* Symbol() { return from_bitset(kSymbol); }
+
+ static Type* Receiver() { return from_bitset(kReceiver); }
+ static Type* Object() { return from_bitset(kObject); }
+ static Type* Array() { return from_bitset(kArray); }
+ static Type* Function() { return from_bitset(kFunction); }
+ static Type* Proxy() { return from_bitset(kProxy); }
+
+ static Type* Class(Handle<Map> map) { return from_handle(map); }
+ static Type* Constant(Handle<HeapObject> value) {
+ ASSERT(!value->IsMap() && !value->IsFixedArray());
+ return from_handle(value);
+ }
+
+ static Type* Union(Handle<Type> type1, Handle<Type> type2);
+ static Type* Optional(Handle<Type> type); // type \/ Undefined
+
+ bool Is(Handle<Type> that);
+ bool Maybe(Handle<Type> that);
+
+ // TODO(rossberg): method to iterate unions?
+
+ private:
+ // A union is a fixed array containing types. Invariants:
+ // - its length is at least 2
+ // - at most one field is a bitset, and it must go into index 0
+ // - no field is a union
+ typedef FixedArray Unioned;
+
+ enum {
+ kNull = 1 << 0,
+ kUndefined = 1 << 1,
+ kBoolean = 1 << 2,
+ kSmi = 1 << 3,
+ kDouble = 1 << 4,
+ kSymbol = 1 << 5,
+ kInternalizedString = 1 << 6,
+ kOtherString = 1 << 7,
+ kArray = 1 << 8,
+ kFunction = 1 << 9,
+ kOtherObject = 1 << 10,
+ kProxy = 1 << 11,
+
+ kOddball = kBoolean | kNull | kUndefined,
+ kNumber = kSmi | kDouble,
+ kString = kInternalizedString | kOtherString,
+ kUniqueName = kSymbol | kInternalizedString,
+ kName = kSymbol | kString,
+ kObject = kArray | kFunction | kOtherObject,
+ kReceiver = kObject | kProxy,
+ kAny = kOddball | kNumber | kName | kReceiver,
+ kNone = 0
+ };
+
+ bool is_bitset() { return this->IsSmi(); }
+ bool is_class() { return this->IsMap(); }
+ bool is_constant() { return !(is_bitset() || is_class() || is_union()); }
+ bool is_union() { return this->IsFixedArray(); }
+
+ int as_bitset() { return Smi::cast(this)->value(); }
+ Handle<Map> as_class() { return Handle<Map>::cast(handle()); }
+ Handle<HeapObject> as_constant() {
+ ASSERT(is_constant());
+ return Handle<HeapObject>::cast(handle());
+ }
+ Handle<Unioned> as_union() { return Handle<Unioned>::cast(handle()); }
+
+ Handle<Type> handle() { return handle_via_isolate_of(this); }
+ Handle<Type> handle_via_isolate_of(Type* type) {
+ ASSERT(type->IsHeapObject());
+ return v8::internal::handle(this, HeapObject::cast(type)->GetIsolate());
+ }
+
+ static Type* from_bitset(int bitset) {
+ return static_cast<Type*>(Object::cast(Smi::FromInt(bitset)));
+ }
+ static Type* from_handle(Handle<HeapObject> handle) {
+ return static_cast<Type*>(Object::cast(*handle));
+ }
+
+ static Handle<Type> union_get(Handle<Unioned> unioned, int i) {
+ Type* type = static_cast<Type*>(unioned->get(i));
+ ASSERT(!type->is_union());
+ return type->handle_via_isolate_of(from_handle(unioned));
+ }
+
+ int LubBitset(); // least upper bound that's a bitset
+ int GlbBitset(); // greatest lower bound that's a bitset
+ bool InUnion(Handle<Unioned> unioned, int current_size);
+ int ExtendUnion(Handle<Unioned> unioned, int current_size);
+};
+
+} } // namespace v8::internal
+
+#endif // V8_TYPES_H_
diff --git a/src/typing.cc b/src/typing.cc
index c2d418f..3e4144e 100644
--- a/src/typing.cc
+++ b/src/typing.cc
@@ -27,7 +27,6 @@
#include "typing.h"
-#include "v8.h"
#include "parser.h" // for CompileTimeValue; TODO(rossberg): should move
#include "scopes.h"
diff --git a/src/version.cc b/src/version.cc
index 82ed285..bfb413f 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,8 +34,8 @@
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION 3
#define MINOR_VERSION 19
-#define BUILD_NUMBER 9
-#define PATCH_LEVEL 2
+#define BUILD_NUMBER 10
+#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 0
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index f5d38f3..bc2e59a 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -30,7 +30,6 @@
#if defined(V8_TARGET_ARCH_X64)
#include "bootstrapper.h"
-#include "builtins-decls.h"
#include "code-stubs.h"
#include "regexp-macro-assembler.h"
#include "stub-cache.h"
@@ -133,7 +132,7 @@
descriptor->register_params_ = registers;
descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
descriptor->deoptimization_handler_ =
- FUNCTION_ADDR(ArrayConstructor_StubFailure);
+ Runtime::FunctionForId(Runtime::kArrayConstructor)->entry;
}
@@ -155,7 +154,7 @@
descriptor->register_params_ = registers;
descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
descriptor->deoptimization_handler_ =
- FUNCTION_ADDR(InternalArrayConstructor_StubFailure);
+ Runtime::FunctionForId(Runtime::kInternalArrayConstructor)->entry;
}
@@ -6756,17 +6755,17 @@
// Calculate the original stack pointer and store it in the second arg.
#ifdef _WIN64
- __ lea(rdx, Operand(rsp, kNumSavedRegisters * kPointerSize));
+ __ lea(rdx, Operand(rsp, (kNumSavedRegisters + 1) * kPointerSize));
#else
- __ lea(rsi, Operand(rsp, kNumSavedRegisters * kPointerSize));
+ __ lea(rsi, Operand(rsp, (kNumSavedRegisters + 1) * kPointerSize));
#endif
// Calculate the function address to the first arg.
#ifdef _WIN64
- __ movq(rcx, Operand(rdx, 0));
+ __ movq(rcx, Operand(rsp, kNumSavedRegisters * kPointerSize));
__ subq(rcx, Immediate(Assembler::kShortCallInstructionLength));
#else
- __ movq(rdi, Operand(rsi, 0));
+ __ movq(rdi, Operand(rsp, kNumSavedRegisters * kPointerSize));
__ subq(rdi, Immediate(Assembler::kShortCallInstructionLength));
#endif
diff --git a/src/x64/regexp-macro-assembler-x64.cc b/src/x64/regexp-macro-assembler-x64.cc
index 012dcc8..4a4a84e 100644
--- a/src/x64/regexp-macro-assembler-x64.cc
+++ b/src/x64/regexp-macro-assembler-x64.cc
@@ -226,101 +226,6 @@
}
-void RegExpMacroAssemblerX64::CheckCharacters(Vector<const uc16> str,
- int cp_offset,
- Label* on_failure,
- bool check_end_of_string) {
-#ifdef DEBUG
- // If input is ASCII, don't even bother calling here if the string to
- // match contains a non-ASCII character.
- if (mode_ == ASCII) {
- ASSERT(String::IsOneByte(str.start(), str.length()));
- }
-#endif
- int byte_length = str.length() * char_size();
- int byte_offset = cp_offset * char_size();
- if (check_end_of_string) {
- // Check that there are at least str.length() characters left in the input.
- __ cmpl(rdi, Immediate(-(byte_offset + byte_length)));
- BranchOrBacktrack(greater, on_failure);
- }
-
- if (on_failure == NULL) {
- // Instead of inlining a backtrack, (re)use the global backtrack target.
- on_failure = &backtrack_label_;
- }
-
- // Do one character test first to minimize loading for the case that
- // we don't match at all (loading more than one character introduces that
- // chance of reading unaligned and reading across cache boundaries).
- // If the first character matches, expect a larger chance of matching the
- // string, and start loading more characters at a time.
- if (mode_ == ASCII) {
- __ cmpb(Operand(rsi, rdi, times_1, byte_offset),
- Immediate(static_cast<int8_t>(str[0])));
- } else {
- // Don't use 16-bit immediate. The size changing prefix throws off
- // pre-decoding.
- __ movzxwl(rax,
- Operand(rsi, rdi, times_1, byte_offset));
- __ cmpl(rax, Immediate(static_cast<int32_t>(str[0])));
- }
- BranchOrBacktrack(not_equal, on_failure);
-
- __ lea(rbx, Operand(rsi, rdi, times_1, 0));
- for (int i = 1, n = str.length(); i < n; ) {
- if (mode_ == ASCII) {
- if (i + 8 <= n) {
- uint64_t combined_chars =
- (static_cast<uint64_t>(str[i + 0]) << 0) ||
- (static_cast<uint64_t>(str[i + 1]) << 8) ||
- (static_cast<uint64_t>(str[i + 2]) << 16) ||
- (static_cast<uint64_t>(str[i + 3]) << 24) ||
- (static_cast<uint64_t>(str[i + 4]) << 32) ||
- (static_cast<uint64_t>(str[i + 5]) << 40) ||
- (static_cast<uint64_t>(str[i + 6]) << 48) ||
- (static_cast<uint64_t>(str[i + 7]) << 56);
- __ movq(rax, combined_chars, RelocInfo::NONE64);
- __ cmpq(rax, Operand(rbx, byte_offset + i));
- i += 8;
- } else if (i + 4 <= n) {
- uint32_t combined_chars =
- (static_cast<uint32_t>(str[i + 0]) << 0) ||
- (static_cast<uint32_t>(str[i + 1]) << 8) ||
- (static_cast<uint32_t>(str[i + 2]) << 16) ||
- (static_cast<uint32_t>(str[i + 3]) << 24);
- __ cmpl(Operand(rbx, byte_offset + i), Immediate(combined_chars));
- i += 4;
- } else {
- __ cmpb(Operand(rbx, byte_offset + i),
- Immediate(static_cast<int8_t>(str[i])));
- i++;
- }
- } else {
- ASSERT(mode_ == UC16);
- if (i + 4 <= n) {
- uint64_t combined_chars = *reinterpret_cast<const uint64_t*>(&str[i]);
- __ movq(rax, combined_chars, RelocInfo::NONE64);
- __ cmpq(rax,
- Operand(rsi, rdi, times_1, byte_offset + i * sizeof(uc16)));
- i += 4;
- } else if (i + 2 <= n) {
- uint32_t combined_chars = *reinterpret_cast<const uint32_t*>(&str[i]);
- __ cmpl(Operand(rsi, rdi, times_1, byte_offset + i * sizeof(uc16)),
- Immediate(combined_chars));
- i += 2;
- } else {
- __ movzxwl(rax,
- Operand(rsi, rdi, times_1, byte_offset + i * sizeof(uc16)));
- __ cmpl(rax, Immediate(str[i]));
- i++;
- }
- }
- BranchOrBacktrack(not_equal, on_failure);
- }
-}
-
-
void RegExpMacroAssemblerX64::CheckGreedyLoop(Label* on_equal) {
Label fallthrough;
__ cmpl(rdi, Operand(backtrack_stackpointer(), 0));
diff --git a/src/x64/regexp-macro-assembler-x64.h b/src/x64/regexp-macro-assembler-x64.h
index 296c866..b230ea4 100644
--- a/src/x64/regexp-macro-assembler-x64.h
+++ b/src/x64/regexp-macro-assembler-x64.h
@@ -55,10 +55,6 @@
Label* on_equal);
virtual void CheckCharacterGT(uc16 limit, Label* on_greater);
virtual void CheckCharacterLT(uc16 limit, Label* on_less);
- virtual void CheckCharacters(Vector<const uc16> str,
- int cp_offset,
- Label* on_failure,
- bool check_end_of_string);
// A "greedy loop" is a loop that is both greedy and with a simple
// body. It has a particularly simple implementation.
virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp
index 0a91ed5..75e4158 100644
--- a/test/cctest/cctest.gyp
+++ b/test/cctest/cctest.gyp
@@ -99,6 +99,7 @@
'test-strtod.cc',
'test-thread-termination.cc',
'test-threads.cc',
+ 'test-types.cc',
'test-unbound-queue.cc',
'test-utils.cc',
'test-version.cc',
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
old mode 100644
new mode 100755
index cb3a38e..d514b1e
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -2007,88 +2007,90 @@
v8::Handle<v8::Object> bottom;
-static v8::Handle<Value> CheckThisIndexedPropertyHandler(
+static void CheckThisIndexedPropertyHandler(
uint32_t index,
- const AccessorInfo& info) {
+ const v8::PropertyCallbackInfo<v8::Value>& info) {
+ CheckReturnValue(info);
ApiTestFuzzer::Fuzz();
CHECK(info.This()->Equals(bottom));
- return v8::Handle<Value>();
}
-static v8::Handle<Value> CheckThisNamedPropertyHandler(
+static void CheckThisNamedPropertyHandler(
Local<String> name,
- const AccessorInfo& info) {
+ const v8::PropertyCallbackInfo<v8::Value>& info) {
+ CheckReturnValue(info);
ApiTestFuzzer::Fuzz();
CHECK(info.This()->Equals(bottom));
- return v8::Handle<Value>();
}
-
-v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
- Local<Value> value,
- const AccessorInfo& info) {
- ApiTestFuzzer::Fuzz();
- CHECK(info.This()->Equals(bottom));
- return v8::Handle<Value>();
-}
-
-
-v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
- Local<Value> value,
- const AccessorInfo& info) {
- ApiTestFuzzer::Fuzz();
- CHECK(info.This()->Equals(bottom));
- return v8::Handle<Value>();
-}
-
-v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
+void CheckThisIndexedPropertySetter(
uint32_t index,
- const AccessorInfo& info) {
+ Local<Value> value,
+ const v8::PropertyCallbackInfo<v8::Value>& info) {
+ CheckReturnValue(info);
ApiTestFuzzer::Fuzz();
CHECK(info.This()->Equals(bottom));
- return v8::Handle<v8::Integer>();
}
-v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
- const AccessorInfo& info) {
- ApiTestFuzzer::Fuzz();
- CHECK(info.This()->Equals(bottom));
- return v8::Handle<v8::Integer>();
-}
-
-
-v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
- uint32_t index,
- const AccessorInfo& info) {
- ApiTestFuzzer::Fuzz();
- CHECK(info.This()->Equals(bottom));
- return v8::Handle<v8::Boolean>();
-}
-
-
-v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
+void CheckThisNamedPropertySetter(
Local<String> property,
- const AccessorInfo& info) {
+ Local<Value> value,
+ const v8::PropertyCallbackInfo<v8::Value>& info) {
+ CheckReturnValue(info);
ApiTestFuzzer::Fuzz();
CHECK(info.This()->Equals(bottom));
- return v8::Handle<v8::Boolean>();
+}
+
+void CheckThisIndexedPropertyQuery(
+ uint32_t index,
+ const v8::PropertyCallbackInfo<v8::Integer>& info) {
+ CheckReturnValue(info);
+ ApiTestFuzzer::Fuzz();
+ CHECK(info.This()->Equals(bottom));
}
-v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
- const AccessorInfo& info) {
+void CheckThisNamedPropertyQuery(
+ Local<String> property,
+ const v8::PropertyCallbackInfo<v8::Integer>& info) {
+ CheckReturnValue(info);
ApiTestFuzzer::Fuzz();
CHECK(info.This()->Equals(bottom));
- return v8::Handle<v8::Array>();
}
-v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
- const AccessorInfo& info) {
+void CheckThisIndexedPropertyDeleter(
+ uint32_t index,
+ const v8::PropertyCallbackInfo<v8::Boolean>& info) {
+ CheckReturnValue(info);
ApiTestFuzzer::Fuzz();
CHECK(info.This()->Equals(bottom));
- return v8::Handle<v8::Array>();
+}
+
+
+void CheckThisNamedPropertyDeleter(
+ Local<String> property,
+ const v8::PropertyCallbackInfo<v8::Boolean>& info) {
+ CheckReturnValue(info);
+ ApiTestFuzzer::Fuzz();
+ CHECK(info.This()->Equals(bottom));
+}
+
+
+void CheckThisIndexedPropertyEnumerator(
+ const v8::PropertyCallbackInfo<v8::Array>& info) {
+ CheckReturnValue(info);
+ ApiTestFuzzer::Fuzz();
+ CHECK(info.This()->Equals(bottom));
+}
+
+
+void CheckThisNamedPropertyEnumerator(
+ const v8::PropertyCallbackInfo<v8::Array>& info) {
+ CheckReturnValue(info);
+ ApiTestFuzzer::Fuzz();
+ CHECK(info.This()->Equals(bottom));
}
@@ -12085,9 +12087,10 @@
static i::Handle<i::JSFunction>* foo_ptr = NULL;
-static int foo_count = 0;
+static int foo_entry_count = 0;
static i::Handle<i::JSFunction>* bar_ptr = NULL;
-static int bar_count = 0;
+static int bar_entry_count = 0;
+static int bar_caller_count = 0;
static void entry_hook(uintptr_t function,
@@ -12097,14 +12100,21 @@
CHECK(code != NULL);
if (bar_ptr != NULL && code == (*bar_ptr)->code())
- ++bar_count;
+ ++bar_entry_count;
if (foo_ptr != NULL && code == (*foo_ptr)->code())
- ++foo_count;
+ ++foo_entry_count;
- // TODO(siggi): Verify return_addr_location.
- // This can be done by capturing JitCodeEvents, but requires an ordered
- // collection.
+ // Let's check whether bar is the caller.
+ if (bar_ptr != NULL) {
+ const v8::internal::byte* caller =
+ *reinterpret_cast<v8::internal::byte**>(return_addr_location);
+
+ if ((*bar_ptr)->code()->instruction_start() <= caller &&
+ (*bar_ptr)->code()->instruction_end() > caller) {
+ ++bar_caller_count;
+ }
+ }
}
@@ -12175,17 +12185,20 @@
CHECK(v8::V8::SetFunctionEntryHook(NULL));
// Reset the entry count to zero and set the entry hook.
- bar_count = 0;
- foo_count = 0;
+ bar_entry_count = 0;
+ bar_caller_count = 0;
+ foo_entry_count = 0;
CHECK(v8::V8::SetFunctionEntryHook(entry_hook));
RunLoopInNewEnv();
- CHECK_EQ(2, bar_count);
- CHECK_EQ(200, foo_count);
+ CHECK_EQ(2, bar_entry_count);
+ CHECK_EQ(200, bar_caller_count);
+ CHECK_EQ(200, foo_entry_count);
// Clear the entry hook and count.
- bar_count = 0;
- foo_count = 0;
+ bar_entry_count = 0;
+ bar_caller_count = 0;
+ foo_entry_count = 0;
v8::V8::SetFunctionEntryHook(NULL);
// Clear the compilation cache to make sure we don't reuse the
@@ -12194,8 +12207,9 @@
// Verify that entry hooking is now disabled.
RunLoopInNewEnv();
- CHECK_EQ(0u, bar_count);
- CHECK_EQ(0u, foo_count);
+ CHECK_EQ(0u, bar_entry_count);
+ CHECK_EQ(0u, bar_caller_count);
+ CHECK_EQ(0u, foo_entry_count);
}
@@ -16867,6 +16881,51 @@
}
+TEST(ContainsOnlyOneByte) {
+ v8::V8::Initialize();
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope scope(isolate);
+ // Make a buffer long enough that it won't automatically be converted.
+ const int length = 200;
+ i::SmartArrayPointer<uint16_t> string_contents(new uint16_t[length]);
+ // Set to contain only one byte.
+ for (int i = 0; i < length-1; i++) {
+ string_contents[i] = 0x41;
+ }
+ string_contents[length-1] = 0;
+ // Simple case.
+ Handle<String> string;
+ string = String::NewExternal(new TestResource(*string_contents));
+ CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
+ // Counter example.
+ string = String::NewFromTwoByte(isolate, *string_contents);
+ CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
+ // Test left right and balanced cons strings.
+ Handle<String> base = String::NewFromUtf8(isolate, "a");
+ Handle<String> left = base;
+ Handle<String> right = base;
+ for (int i = 0; i < 1000; i++) {
+ left = String::Concat(base, left);
+ right = String::Concat(right, base);
+ }
+ Handle<String> balanced = String::Concat(left, base);
+ balanced = String::Concat(balanced, right);
+ Handle<String> cons_strings[] = {left, balanced, right};
+ Handle<String> two_byte =
+ String::NewExternal(new TestResource(*string_contents));
+ for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) {
+ // Base assumptions.
+ string = cons_strings[i];
+ CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
+ // Test left and right concatentation.
+ string = String::Concat(two_byte, cons_strings[i]);
+ CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
+ string = String::Concat(cons_strings[i], two_byte);
+ CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
+ }
+}
+
+
// Failed access check callback that performs a GC on each invocation.
void FailedAccessCheckCallbackGC(Local<v8::Object> target,
v8::AccessType type,
diff --git a/test/cctest/test-cpu-profiler.cc b/test/cctest/test-cpu-profiler.cc
index 901c116..a4a525d 100644
--- a/test/cctest/test-cpu-profiler.cc
+++ b/test/cctest/test-cpu-profiler.cc
@@ -653,12 +653,14 @@
explicit FooAccessorsData(int min_duration_ms)
: min_duration_ms_(min_duration_ms),
getter_duration_(0),
- setter_duration_(0) {}
+ setter_duration_(0),
+ getter_iterations_(0),
+ setter_iterations_(0) {}
static v8::Handle<v8::Value> Getter(v8::Local<v8::String> name,
const v8::AccessorInfo& info) {
FooAccessorsData* data = fromInfo(info);
- data->getter_duration_ = data->Wait();
+ data->getter_duration_ = data->Wait(&data->getter_iterations_);
return v8::Int32::New(2013);
}
@@ -666,20 +668,21 @@
v8::Local<v8::Value> value,
const v8::AccessorInfo& info) {
FooAccessorsData* data = fromInfo(info);
- data->setter_duration_ = data->Wait();
+ data->setter_duration_ = data->Wait(&data->setter_iterations_);
}
void PrintAccessorTime() {
- i::OS::Print("getter: %f ms; setter: %f ms\n", getter_duration_,
- setter_duration_);
+ i::OS::Print("getter: %f ms (%d); setter: %f ms (%d)\n", getter_duration_,
+ getter_iterations_, setter_duration_, setter_iterations_);
}
private:
- double Wait() {
+ double Wait(int* iterations) {
double start = i::OS::TimeCurrentMillis();
double duration = 0;
while (duration < min_duration_ms_) {
duration = i::OS::TimeCurrentMillis() - start;
+ ++*iterations;
}
return duration;
}
@@ -692,6 +695,8 @@
int min_duration_ms_;
double getter_duration_;
double setter_duration_;
+ int getter_iterations_;
+ int setter_iterations_;
};
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
index b580f4b..6367c74 100644
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -1036,7 +1036,7 @@
CHECK_EQ(scope->inner_scopes()->length(), 1);
i::Scope* inner_scope = scope->inner_scopes()->at(0);
- CHECK_EQ(inner_scope->type(), source_data[i].scope_type);
+ CHECK_EQ(inner_scope->scope_type(), source_data[i].scope_type);
CHECK_EQ(inner_scope->start_position(), kPrefixLen);
// The end position of a token is one position after the last
// character belonging to that token.
diff --git a/test/cctest/test-regexp.cc b/test/cctest/test-regexp.cc
index 6bcf5f5..ac62b75 100644
--- a/test/cctest/test-regexp.cc
+++ b/test/cctest/test-regexp.cc
@@ -784,15 +784,22 @@
ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 4,
Isolate::Current()->runtime_zone());
- uc16 foo_chars[3] = {'f', 'o', 'o'};
- Vector<const uc16> foo(foo_chars, 3);
-
- Label fail;
- m.CheckCharacters(foo, 0, &fail, true);
+ Label fail, backtrack;
+ m.PushBacktrack(&fail);
+ m.CheckNotAtStart(NULL);
+ m.LoadCurrentCharacter(2, NULL);
+ m.CheckNotCharacter('o', NULL);
+ m.LoadCurrentCharacter(1, NULL, false);
+ m.CheckNotCharacter('o', NULL);
+ m.LoadCurrentCharacter(0, NULL, false);
+ m.CheckNotCharacter('f', NULL);
m.WriteCurrentPositionToRegister(0, 0);
+ m.WriteCurrentPositionToRegister(1, 3);
m.AdvanceCurrentPosition(3);
- m.WriteCurrentPositionToRegister(1, 0);
+ m.PushBacktrack(&backtrack);
m.Succeed();
+ m.Bind(&backtrack);
+ m.Backtrack();
m.Bind(&fail);
m.Fail();
@@ -842,15 +849,22 @@
ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::UC16, 4,
Isolate::Current()->runtime_zone());
- uc16 foo_chars[3] = {'f', 'o', 'o'};
- Vector<const uc16> foo(foo_chars, 3);
-
- Label fail;
- m.CheckCharacters(foo, 0, &fail, true);
+ Label fail, backtrack;
+ m.PushBacktrack(&fail);
+ m.CheckNotAtStart(NULL);
+ m.LoadCurrentCharacter(2, NULL);
+ m.CheckNotCharacter('o', NULL);
+ m.LoadCurrentCharacter(1, NULL, false);
+ m.CheckNotCharacter('o', NULL);
+ m.LoadCurrentCharacter(0, NULL, false);
+ m.CheckNotCharacter('f', NULL);
m.WriteCurrentPositionToRegister(0, 0);
+ m.WriteCurrentPositionToRegister(1, 3);
m.AdvanceCurrentPosition(3);
- m.WriteCurrentPositionToRegister(1, 0);
+ m.PushBacktrack(&backtrack);
m.Succeed();
+ m.Bind(&backtrack);
+ m.Backtrack();
m.Bind(&fail);
m.Fail();
@@ -1349,36 +1363,33 @@
RegExpMacroAssemblerIrregexp m(Vector<byte>(codes, 1024),
Isolate::Current()->runtime_zone());
// ^f(o)o.
- Label fail, fail2, start;
- uc16 foo_chars[3];
- foo_chars[0] = 'f';
- foo_chars[1] = 'o';
- foo_chars[2] = 'o';
- Vector<const uc16> foo(foo_chars, 3);
+ Label start, fail, backtrack;
+
m.SetRegister(4, 42);
m.PushRegister(4, RegExpMacroAssembler::kNoStackLimitCheck);
m.AdvanceRegister(4, 42);
m.GoTo(&start);
m.Fail();
m.Bind(&start);
- m.PushBacktrack(&fail2);
- m.CheckCharacters(foo, 0, &fail, true);
+ m.PushBacktrack(&fail);
+ m.CheckNotAtStart(NULL);
+ m.LoadCurrentCharacter(0, NULL);
+ m.CheckNotCharacter('f', NULL);
+ m.LoadCurrentCharacter(1, NULL);
+ m.CheckNotCharacter('o', NULL);
+ m.LoadCurrentCharacter(2, NULL);
+ m.CheckNotCharacter('o', NULL);
m.WriteCurrentPositionToRegister(0, 0);
- m.PushCurrentPosition();
+ m.WriteCurrentPositionToRegister(1, 3);
+ m.WriteCurrentPositionToRegister(2, 1);
+ m.WriteCurrentPositionToRegister(3, 2);
m.AdvanceCurrentPosition(3);
- m.WriteCurrentPositionToRegister(1, 0);
- m.PopCurrentPosition();
- m.AdvanceCurrentPosition(1);
- m.WriteCurrentPositionToRegister(2, 0);
- m.AdvanceCurrentPosition(1);
- m.WriteCurrentPositionToRegister(3, 0);
+ m.PushBacktrack(&backtrack);
m.Succeed();
-
- m.Bind(&fail);
+ m.Bind(&backtrack);
+ m.ClearRegisters(2, 3);
m.Backtrack();
- m.Succeed();
-
- m.Bind(&fail2);
+ m.Bind(&fail);
m.PopRegister(0);
m.Fail();
diff --git a/test/cctest/test-types.cc b/test/cctest/test-types.cc
new file mode 100644
index 0000000..d5852e0
--- /dev/null
+++ b/test/cctest/test-types.cc
@@ -0,0 +1,521 @@
+// Copyright 2013 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 "cctest.h"
+#include "types.h"
+
+using namespace v8::internal;
+
+// Testing auxiliaries (breaking the Type abstraction).
+static bool IsBitset(Type* type) { return type->IsSmi(); }
+static bool IsClass(Type* type) { return type->IsMap(); }
+static bool IsUnion(Type* type) { return type->IsFixedArray(); }
+static bool IsConstant(Type* type) {
+ return !(IsBitset(type) || IsClass(type) || IsUnion(type));
+}
+
+static int AsBitset(Type* type) { return Smi::cast(type)->value(); }
+static Map* AsClass(Type* type) { return Map::cast(type); }
+static HeapObject* AsConstant(Type* type) { return HeapObject::cast(type); }
+static FixedArray* AsUnion(Type* type) { return FixedArray::cast(type); }
+
+class HandlifiedTypes {
+ public:
+ explicit HandlifiedTypes(Isolate* isolate) :
+ None(Type::None(), isolate),
+ Any(Type::Any(), isolate),
+ Oddball(Type::Oddball(), isolate),
+ Boolean(Type::Boolean(), isolate),
+ Null(Type::Null(), isolate),
+ Undefined(Type::Undefined(), isolate),
+ Number(Type::Number(), isolate),
+ Smi(Type::Smi(), isolate),
+ Double(Type::Double(), isolate),
+ Name(Type::Name(), isolate),
+ UniqueName(Type::UniqueName(), isolate),
+ String(Type::String(), isolate),
+ InternalizedString(Type::InternalizedString(), isolate),
+ Symbol(Type::Symbol(), isolate),
+ Receiver(Type::Receiver(), isolate),
+ Object(Type::Object(), isolate),
+ Array(Type::Array(), isolate),
+ Function(Type::Function(), isolate),
+ Proxy(Type::Proxy(), isolate),
+ object_map(isolate->factory()->NewMap(JS_OBJECT_TYPE, 3 * kPointerSize)),
+ array_map(isolate->factory()->NewMap(JS_ARRAY_TYPE, 4 * kPointerSize)),
+ isolate_(isolate) {
+ object1 = isolate->factory()->NewJSObjectFromMap(object_map);
+ object2 = isolate->factory()->NewJSObjectFromMap(object_map);
+ array = isolate->factory()->NewJSArray(20);
+ ObjectClass = handle(Type::Class(object_map), isolate);
+ ArrayClass = handle(Type::Class(array_map), isolate);
+ ObjectConstant1 = handle(Type::Constant(object1), isolate);
+ ObjectConstant2 = handle(Type::Constant(object2), isolate);
+ ArrayConstant = handle(Type::Constant(array), isolate);
+ }
+
+ Handle<Type> None;
+ Handle<Type> Any;
+ Handle<Type> Oddball;
+ Handle<Type> Boolean;
+ Handle<Type> Null;
+ Handle<Type> Undefined;
+ Handle<Type> Number;
+ Handle<Type> Smi;
+ Handle<Type> Double;
+ Handle<Type> Name;
+ Handle<Type> UniqueName;
+ Handle<Type> String;
+ Handle<Type> InternalizedString;
+ Handle<Type> Symbol;
+ Handle<Type> Receiver;
+ Handle<Type> Object;
+ Handle<Type> Array;
+ Handle<Type> Function;
+ Handle<Type> Proxy;
+
+ Handle<Type> ObjectClass;
+ Handle<Type> ArrayClass;
+ Handle<Type> ObjectConstant1;
+ Handle<Type> ObjectConstant2;
+ Handle<Type> ArrayConstant;
+
+ Handle<Map> object_map;
+ Handle<Map> array_map;
+
+ Handle<JSObject> object1;
+ Handle<JSObject> object2;
+ Handle<JSArray> array;
+
+ Handle<Type> Union(Handle<Type> type1, Handle<Type> type2) {
+ return handle(Type::Union(type1, type2), isolate_);
+ }
+
+ private:
+ Isolate* isolate_;
+};
+
+
+TEST(Bitset) {
+ CcTest::InitializeVM();
+ Isolate* isolate = Isolate::Current();
+ HandleScope scope(isolate);
+ HandlifiedTypes T(isolate);
+
+ CHECK(IsBitset(*T.None));
+ CHECK(IsBitset(*T.Any));
+ CHECK(IsBitset(*T.String));
+ CHECK(IsBitset(*T.Object));
+
+ CHECK(IsBitset(Type::Union(T.String, T.Number)));
+ CHECK(IsBitset(Type::Union(T.String, T.Receiver)));
+ CHECK(IsBitset(Type::Optional(T.Object)));
+
+ CHECK_EQ(0, AsBitset(*T.None));
+ CHECK_EQ(AsBitset(*T.Number) | AsBitset(*T.String),
+ AsBitset(Type::Union(T.String, T.Number)));
+ CHECK_EQ(AsBitset(*T.Receiver),
+ AsBitset(Type::Union(T.Receiver, T.Object)));
+ CHECK_EQ(AsBitset(*T.String) | AsBitset(*T.Undefined),
+ AsBitset(Type::Optional(T.String)));
+}
+
+
+TEST(Class) {
+ CcTest::InitializeVM();
+ Isolate* isolate = Isolate::Current();
+ HandleScope scope(isolate);
+ HandlifiedTypes T(isolate);
+
+ CHECK(IsClass(*T.ObjectClass));
+ CHECK(IsClass(*T.ArrayClass));
+
+ CHECK(*T.object_map == AsClass(*T.ObjectClass));
+ CHECK(*T.array_map == AsClass(*T.ArrayClass));
+}
+
+
+TEST(Constant) {
+ CcTest::InitializeVM();
+ Isolate* isolate = Isolate::Current();
+ HandleScope scope(isolate);
+ HandlifiedTypes T(isolate);
+
+ CHECK(IsConstant(*T.ObjectConstant1));
+ CHECK(IsConstant(*T.ObjectConstant2));
+ CHECK(IsConstant(*T.ArrayConstant));
+
+ CHECK(*T.object1 == AsConstant(*T.ObjectConstant1));
+ CHECK(*T.object2 == AsConstant(*T.ObjectConstant2));
+ CHECK(*T.object1 != AsConstant(*T.ObjectConstant2));
+ CHECK(*T.array == AsConstant(*T.ArrayConstant));
+}
+
+
+static void CheckSub(Handle<Type> type1, Handle<Type> type2) {
+ CHECK(type1->Is(type2));
+ CHECK(!type2->Is(type1));
+ if (IsBitset(*type1) && IsBitset(*type2)) {
+ CHECK_NE(AsBitset(*type1), AsBitset(*type2));
+ }
+}
+
+static void CheckUnordered(Handle<Type> type1, Handle<Type> type2) {
+ CHECK(!type1->Is(type2));
+ CHECK(!type2->Is(type1));
+ if (IsBitset(*type1) && IsBitset(*type2)) {
+ CHECK_NE(AsBitset(*type1), AsBitset(*type2));
+ }
+}
+
+TEST(Is) {
+ CcTest::InitializeVM();
+ Isolate* isolate = Isolate::Current();
+ HandleScope scope(isolate);
+ HandlifiedTypes T(isolate);
+
+ // Reflexivity
+ CHECK(T.None->Is(T.None));
+ CHECK(T.Any->Is(T.Any));
+ CHECK(T.Object->Is(T.Object));
+
+ CHECK(T.ObjectClass->Is(T.ObjectClass));
+ CHECK(T.ObjectConstant1->Is(T.ObjectConstant1));
+
+ // Symmetry and Transitivity
+ CheckSub(T.None, T.Number);
+ CheckSub(T.None, T.Any);
+
+ CheckSub(T.Oddball, T.Any);
+ CheckSub(T.Boolean, T.Oddball);
+ CheckSub(T.Null, T.Oddball);
+ CheckSub(T.Undefined, T.Oddball);
+ CheckUnordered(T.Boolean, T.Null);
+ CheckUnordered(T.Undefined, T.Null);
+ CheckUnordered(T.Boolean, T.Undefined);
+
+ CheckSub(T.Number, T.Any);
+ CheckSub(T.Smi, T.Number);
+ CheckSub(T.Double, T.Number);
+ CheckUnordered(T.Smi, T.Double);
+
+ CheckSub(T.Name, T.Any);
+ CheckSub(T.UniqueName, T.Any);
+ CheckSub(T.UniqueName, T.Name);
+ CheckSub(T.String, T.Name);
+ CheckSub(T.InternalizedString, T.String);
+ CheckSub(T.InternalizedString, T.UniqueName);
+ CheckSub(T.InternalizedString, T.Name);
+ CheckSub(T.Symbol, T.UniqueName);
+ CheckSub(T.Symbol, T.Name);
+ CheckUnordered(T.String, T.UniqueName);
+ CheckUnordered(T.String, T.Symbol);
+ CheckUnordered(T.InternalizedString, T.Symbol);
+
+ CheckSub(T.Receiver, T.Any);
+ CheckSub(T.Object, T.Any);
+ CheckSub(T.Object, T.Receiver);
+ CheckSub(T.Array, T.Object);
+ CheckSub(T.Function, T.Object);
+ CheckSub(T.Proxy, T.Receiver);
+ CheckUnordered(T.Object, T.Proxy);
+ CheckUnordered(T.Array, T.Function);
+
+ // Structured subtyping
+ CheckSub(T.ObjectClass, T.Object);
+ CheckSub(T.ArrayClass, T.Object);
+ CheckUnordered(T.ObjectClass, T.ArrayClass);
+
+ CheckSub(T.ObjectConstant1, T.Object);
+ CheckSub(T.ObjectConstant2, T.Object);
+ CheckSub(T.ArrayConstant, T.Object);
+ CheckSub(T.ArrayConstant, T.Array);
+ CheckUnordered(T.ObjectConstant1, T.ObjectConstant2);
+ CheckUnordered(T.ObjectConstant1, T.ArrayConstant);
+
+ CheckUnordered(T.ObjectConstant1, T.ObjectClass);
+ CheckUnordered(T.ObjectConstant2, T.ObjectClass);
+ CheckUnordered(T.ObjectConstant1, T.ArrayClass);
+ CheckUnordered(T.ObjectConstant2, T.ArrayClass);
+ CheckUnordered(T.ArrayConstant, T.ObjectClass);
+}
+
+
+static void CheckOverlap(Handle<Type> type1, Handle<Type> type2) {
+ CHECK(type1->Maybe(type2));
+ CHECK(type2->Maybe(type1));
+ if (IsBitset(*type1) && IsBitset(*type2)) {
+ CHECK_NE(0, AsBitset(*type1) & AsBitset(*type2));
+ }
+}
+
+static void CheckDisjoint(Handle<Type> type1, Handle<Type> type2) {
+ CHECK(!type1->Is(type2));
+ CHECK(!type2->Is(type1));
+ CHECK(!type1->Maybe(type2));
+ CHECK(!type2->Maybe(type1));
+ if (IsBitset(*type1) && IsBitset(*type2)) {
+ CHECK_EQ(0, AsBitset(*type1) & AsBitset(*type2));
+ }
+}
+
+TEST(Maybe) {
+ CcTest::InitializeVM();
+ Isolate* isolate = Isolate::Current();
+ HandleScope scope(isolate);
+ HandlifiedTypes T(isolate);
+
+ CheckOverlap(T.Any, T.Any);
+ CheckOverlap(T.Object, T.Object);
+
+ CheckOverlap(T.Oddball, T.Any);
+ CheckOverlap(T.Boolean, T.Oddball);
+ CheckOverlap(T.Null, T.Oddball);
+ CheckOverlap(T.Undefined, T.Oddball);
+ CheckDisjoint(T.Boolean, T.Null);
+ CheckDisjoint(T.Undefined, T.Null);
+ CheckDisjoint(T.Boolean, T.Undefined);
+
+ CheckOverlap(T.Number, T.Any);
+ CheckOverlap(T.Smi, T.Number);
+ CheckOverlap(T.Double, T.Number);
+ CheckDisjoint(T.Smi, T.Double);
+
+ CheckOverlap(T.Name, T.Any);
+ CheckOverlap(T.UniqueName, T.Any);
+ CheckOverlap(T.UniqueName, T.Name);
+ CheckOverlap(T.String, T.Name);
+ CheckOverlap(T.InternalizedString, T.String);
+ CheckOverlap(T.InternalizedString, T.UniqueName);
+ CheckOverlap(T.InternalizedString, T.Name);
+ CheckOverlap(T.Symbol, T.UniqueName);
+ CheckOverlap(T.Symbol, T.Name);
+ CheckOverlap(T.String, T.UniqueName);
+ CheckDisjoint(T.String, T.Symbol);
+ CheckDisjoint(T.InternalizedString, T.Symbol);
+
+ CheckOverlap(T.Receiver, T.Any);
+ CheckOverlap(T.Object, T.Any);
+ CheckOverlap(T.Object, T.Receiver);
+ CheckOverlap(T.Array, T.Object);
+ CheckOverlap(T.Function, T.Object);
+ CheckOverlap(T.Proxy, T.Receiver);
+ CheckDisjoint(T.Object, T.Proxy);
+ CheckDisjoint(T.Array, T.Function);
+
+ CheckOverlap(T.ObjectClass, T.Object);
+ CheckOverlap(T.ArrayClass, T.Object);
+ CheckOverlap(T.ObjectClass, T.ObjectClass);
+ CheckOverlap(T.ArrayClass, T.ArrayClass);
+ CheckDisjoint(T.ObjectClass, T.ArrayClass);
+
+ CheckOverlap(T.ObjectConstant1, T.Object);
+ CheckOverlap(T.ObjectConstant2, T.Object);
+ CheckOverlap(T.ArrayConstant, T.Object);
+ CheckOverlap(T.ArrayConstant, T.Array);
+ CheckOverlap(T.ObjectConstant1, T.ObjectConstant1);
+ CheckDisjoint(T.ObjectConstant1, T.ObjectConstant2);
+ CheckDisjoint(T.ObjectConstant1, T.ArrayConstant);
+
+ CheckDisjoint(T.ObjectConstant1, T.ObjectClass);
+ CheckDisjoint(T.ObjectConstant2, T.ObjectClass);
+ CheckDisjoint(T.ObjectConstant1, T.ArrayClass);
+ CheckDisjoint(T.ObjectConstant2, T.ArrayClass);
+ CheckDisjoint(T.ArrayConstant, T.ObjectClass);
+}
+
+
+static void CheckEqual(Handle<Type> type1, Handle<Type> type2) {
+ CHECK_EQ(IsBitset(*type1), IsBitset(*type2));
+ CHECK_EQ(IsClass(*type1), IsClass(*type2));
+ CHECK_EQ(IsConstant(*type1), IsConstant(*type2));
+ CHECK_EQ(IsUnion(*type1), IsUnion(*type2));
+ if (IsBitset(*type1)) {
+ CHECK_EQ(AsBitset(*type1), AsBitset(*type2));
+ } else if (IsClass(*type1)) {
+ CHECK_EQ(AsClass(*type1), AsClass(*type2));
+ } else if (IsConstant(*type1)) {
+ CHECK_EQ(AsConstant(*type1), AsConstant(*type2));
+ } else if (IsUnion(*type1)) {
+ CHECK_EQ(AsUnion(*type1)->length(), AsUnion(*type2)->length());
+ }
+ CHECK(type1->Is(type2));
+ CHECK(type2->Is(type1));
+}
+
+TEST(Union) {
+ CcTest::InitializeVM();
+ Isolate* isolate = Isolate::Current();
+ HandleScope scope(isolate);
+ HandlifiedTypes T(isolate);
+
+ // Bitset-bitset
+ CHECK(IsBitset(Type::Union(T.Object, T.Number)));
+ CHECK(IsBitset(Type::Union(T.Object, T.Object)));
+ CHECK(IsBitset(Type::Union(T.Any, T.None)));
+
+ CheckEqual(T.Union(T.None, T.Number), T.Number);
+ CheckEqual(T.Union(T.Object, T.Proxy), T.Receiver);
+ CheckEqual(T.Union(T.Number, T.String), T.Union(T.String, T.Number));
+ CheckSub(T.Union(T.Number, T.String), T.Any);
+
+ // Class-class
+ CHECK(IsClass(Type::Union(T.ObjectClass, T.ObjectClass)));
+ CHECK(IsUnion(Type::Union(T.ObjectClass, T.ArrayClass)));
+
+ CheckEqual(T.Union(T.ObjectClass, T.ObjectClass), T.ObjectClass);
+ CheckSub(T.ObjectClass, T.Union(T.ObjectClass, T.ArrayClass));
+ CheckSub(T.ArrayClass, T.Union(T.ObjectClass, T.ArrayClass));
+ CheckSub(T.Union(T.ObjectClass, T.ArrayClass), T.Object);
+ CheckUnordered(T.Union(T.ObjectClass, T.ArrayClass), T.Array);
+ CheckOverlap(T.Union(T.ObjectClass, T.ArrayClass), T.Array);
+ CheckDisjoint(T.Union(T.ObjectClass, T.ArrayClass), T.Number);
+
+ // Constant-constant
+ CHECK(IsConstant(Type::Union(T.ObjectConstant1, T.ObjectConstant1)));
+ CHECK(IsUnion(Type::Union(T.ObjectConstant1, T.ObjectConstant2)));
+
+ CheckEqual(T.Union(T.ObjectConstant1, T.ObjectConstant1), T.ObjectConstant1);
+ CheckSub(T.ObjectConstant1, T.Union(T.ObjectConstant1, T.ObjectConstant2));
+ CheckSub(T.ObjectConstant2, T.Union(T.ObjectConstant1, T.ObjectConstant2));
+ CheckSub(T.Union(T.ObjectConstant1, T.ObjectConstant2), T.Object);
+ CheckUnordered(T.Union(T.ObjectConstant1, T.ObjectConstant2), T.ObjectClass);
+ CheckUnordered(T.Union(T.ObjectConstant1, T.ArrayConstant), T.Array);
+ CheckOverlap(T.Union(T.ObjectConstant1, T.ArrayConstant), T.Array);
+ CheckDisjoint(T.Union(T.ObjectConstant1, T.ArrayConstant), T.Number);
+ CheckDisjoint(T.Union(T.ObjectConstant1, T.ArrayConstant), T.ObjectClass);
+
+ // Bitset-class
+ CHECK(IsBitset(Type::Union(T.ObjectClass, T.Object)));
+ CHECK(IsUnion(Type::Union(T.ObjectClass, T.Number)));
+
+ CheckEqual(T.Union(T.ObjectClass, T.Object), T.Object);
+ CheckSub(T.Union(T.ObjectClass, T.Number), T.Any);
+ CheckSub(T.Union(T.ObjectClass, T.Smi), T.Union(T.Object, T.Number));
+ CheckSub(T.Union(T.ObjectClass, T.Array), T.Object);
+ CheckUnordered(T.Union(T.ObjectClass, T.String), T.Array);
+ CheckOverlap(T.Union(T.ObjectClass, T.String), T.Object);
+ CheckDisjoint(T.Union(T.ObjectClass, T.String), T.Number);
+
+ // Bitset-constant
+ CHECK(IsBitset(Type::Union(T.ObjectConstant1, T.Object)));
+ CHECK(IsUnion(Type::Union(T.ObjectConstant2, T.Number)));
+
+ CheckEqual(T.Union(T.ObjectConstant1, T.Object), T.Object);
+ CheckSub(T.Union(T.ObjectConstant1, T.Number), T.Any);
+ CheckSub(T.Union(T.ObjectConstant1, T.Smi), T.Union(T.Object, T.Number));
+ CheckSub(T.Union(T.ObjectConstant1, T.Array), T.Object);
+ CheckUnordered(T.Union(T.ObjectConstant1, T.String), T.Array);
+ CheckOverlap(T.Union(T.ObjectConstant1, T.String), T.Object);
+ CheckDisjoint(T.Union(T.ObjectConstant1, T.String), T.Number);
+
+ // Class-constant
+ CHECK(IsUnion(Type::Union(T.ObjectConstant1, T.ObjectClass)));
+ CHECK(IsUnion(Type::Union(T.ArrayClass, T.ObjectConstant2)));
+
+ CheckSub(T.Union(T.ObjectConstant1, T.ArrayClass), T.Object);
+ CheckSub(T.ObjectConstant1, T.Union(T.ObjectConstant1, T.ArrayClass));
+ CheckSub(T.ArrayClass, T.Union(T.ObjectConstant1, T.ArrayClass));
+ CheckUnordered(T.ObjectClass, T.Union(T.ObjectConstant1, T.ArrayClass));
+ CheckSub(
+ T.Union(T.ObjectConstant1, T.ArrayClass), T.Union(T.Array, T.Object));
+ CheckUnordered(T.Union(T.ObjectConstant1, T.ArrayClass), T.ArrayConstant);
+ CheckDisjoint(T.Union(T.ObjectConstant1, T.ArrayClass), T.ObjectConstant2);
+ CheckDisjoint(T.Union(T.ObjectConstant1, T.ArrayClass), T.ObjectClass);
+
+ // Bitset-union
+ CHECK(IsBitset(
+ Type::Union(T.Object, T.Union(T.ObjectConstant1, T.ObjectClass))));
+ CHECK(IsUnion(
+ Type::Union(T.Union(T.ArrayClass, T.ObjectConstant2), T.Number)));
+
+ CheckEqual(
+ T.Union(T.Object, T.Union(T.ObjectConstant1, T.ObjectClass)),
+ T.Object);
+ CheckEqual(
+ T.Union(T.Union(T.ArrayClass, T.ObjectConstant1), T.Number),
+ T.Union(T.ObjectConstant1, T.Union(T.Number, T.ArrayClass)));
+ CheckSub(
+ T.Double,
+ T.Union(T.Union(T.ArrayClass, T.ObjectConstant1), T.Number));
+ CheckSub(
+ T.ObjectConstant1,
+ T.Union(T.Union(T.ArrayClass, T.ObjectConstant1), T.Double));
+ CheckSub(
+ T.Union(T.Union(T.ArrayClass, T.ObjectConstant1), T.Double),
+ T.Any);
+ CheckSub(
+ T.Union(T.Union(T.ArrayClass, T.ObjectConstant1), T.Double),
+ T.Union(T.ObjectConstant1, T.Union(T.Number, T.ArrayClass)));
+
+ // Class-union
+ CHECK(IsUnion(
+ Type::Union(T.Union(T.ArrayClass, T.ObjectConstant2), T.ArrayClass)));
+ CHECK(IsUnion(
+ Type::Union(T.Union(T.ArrayClass, T.ObjectConstant2), T.ObjectClass)));
+
+ CheckEqual(
+ T.Union(T.ObjectClass, T.Union(T.ObjectConstant1, T.ObjectClass)),
+ T.Union(T.ObjectClass, T.ObjectConstant1));
+ CheckSub(
+ T.Union(T.ObjectClass, T.Union(T.ObjectConstant1, T.ObjectClass)),
+ T.Object);
+ CheckEqual(
+ T.Union(T.Union(T.ArrayClass, T.ObjectConstant2), T.ArrayClass),
+ T.Union(T.ArrayClass, T.ObjectConstant2));
+
+ // Constant-union
+ CHECK(IsUnion(Type::Union(
+ T.ObjectConstant1, T.Union(T.ObjectConstant1, T.ObjectConstant2))));
+ CHECK(IsUnion(Type::Union(
+ T.Union(T.ArrayConstant, T.ObjectClass), T.ObjectConstant1)));
+ CHECK(IsUnion(Type::Union(
+ T.Union(T.ArrayConstant, T.ObjectConstant2), T.ObjectConstant1)));
+
+ CheckEqual(
+ T.Union(T.ObjectConstant1, T.Union(T.ObjectConstant1, T.ObjectConstant2)),
+ T.Union(T.ObjectConstant2, T.ObjectConstant1));
+ CheckEqual(
+ T.Union(T.Union(T.ArrayConstant, T.ObjectConstant2), T.ObjectConstant1),
+ T.Union(T.ObjectConstant2, T.Union(T.ArrayConstant, T.ObjectConstant1)));
+
+ // Union-union
+ CHECK(IsBitset(
+ Type::Union(T.Union(T.Number, T.ArrayClass), T.Union(T.Smi, T.Array))));
+
+ CheckEqual(
+ T.Union(T.Union(T.ObjectConstant2, T.ObjectConstant1),
+ T.Union(T.ObjectConstant1, T.ObjectConstant2)),
+ T.Union(T.ObjectConstant2, T.ObjectConstant1));
+ CheckEqual(
+ T.Union(T.Union(T.ObjectConstant2, T.ArrayConstant),
+ T.Union(T.ObjectConstant1, T.ArrayConstant)),
+ T.Union(T.Union(T.ObjectConstant1, T.ObjectConstant2), T.ArrayConstant));
+ CheckEqual(
+ T.Union(T.Union(T.Number, T.ArrayClass), T.Union(T.Smi, T.Array)),
+ T.Union(T.Number, T.Array));
+}
diff --git a/test/mjsunit/allocation-site-info.js b/test/mjsunit/allocation-site-info.js
index 4560531..f533d61 100644
--- a/test/mjsunit/allocation-site-info.js
+++ b/test/mjsunit/allocation-site-info.js
@@ -281,6 +281,23 @@
obj = newarraycase_list_smiobj(2);
assertKind(elements_kind.fast, obj);
+ function newarraycase_onearg(len, value) {
+ var a = new Array(len);
+ a[0] = value;
+ return a;
+ }
+
+ obj = newarraycase_onearg(5, 3.5);
+ assertKind(elements_kind.fast_double, obj);
+ obj = newarraycase_onearg(10, 5);
+ assertKind(elements_kind.fast_double, obj);
+ obj = newarraycase_onearg(0, 5);
+ assertKind(elements_kind.fast_double, obj);
+ // Now pass a length that forces the dictionary path.
+ obj = newarraycase_onearg(100000, 5);
+ assertKind(elements_kind.dictionary, obj);
+ assertTrue(obj.length == 100000);
+
// Verify that cross context calls work
var realmA = Realm.current();
var realmB = Realm.create();
diff --git a/test/mjsunit/fuzz-natives-part2.js b/test/mjsunit/fuzz-natives-part2.js
index 50ca5c2..d5358af 100644
--- a/test/mjsunit/fuzz-natives-part2.js
+++ b/test/mjsunit/fuzz-natives-part2.js
@@ -162,6 +162,8 @@
"ResolvePossiblyDirectEval": true,
"Log": true,
"DeclareGlobals": true,
+ "ArrayConstructor": true,
+ "InternalArrayConstructor": true,
"PromoteScheduledException": true,
"DeleteHandleScopeExtensions": true,
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index 9b90cba..ed37e72 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -456,6 +456,8 @@
'../../src/transitions.h',
'../../src/type-info.cc',
'../../src/type-info.h',
+ '../../src/types.cc',
+ '../../src/types.h',
'../../src/typing.cc',
'../../src/typing.h',
'../../src/unbound-queue-inl.h',