blob: fd866bf85b4721713926fa199a8aeaf4d30e97dc [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "compiler.h"
38#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000039#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000043#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000045#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000046#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000047#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000048#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000049#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000050#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000051#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000052#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000053#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000054#include "smart-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000055#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000056#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000057#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000058#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000059
kasperl@chromium.org71affb52009-05-26 05:44:31 +000060namespace v8 {
61namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000062
63
ager@chromium.org3e875802009-06-29 08:26:34 +000064#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000065 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000066
67// Cast the given object to a value of the specified type and store
68// it in a variable with the given name. If the object is not of the
69// expected type call IllegalOperation and return.
70#define CONVERT_CHECKED(Type, name, obj) \
71 RUNTIME_ASSERT(obj->Is##Type()); \
72 Type* name = Type::cast(obj);
73
74#define CONVERT_ARG_CHECKED(Type, name, index) \
75 RUNTIME_ASSERT(args[index]->Is##Type()); \
76 Handle<Type> name = args.at<Type>(index);
77
kasper.lundbd3ec4e2008-07-09 11:06:54 +000078// Cast the given object to a boolean and store it in a variable with
79// the given name. If the object is not a boolean call IllegalOperation
80// and return.
81#define CONVERT_BOOLEAN_CHECKED(name, obj) \
82 RUNTIME_ASSERT(obj->IsBoolean()); \
83 bool name = (obj)->IsTrue();
84
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000085// Cast the given argument to a Smi and store its value in an int variable
86// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000087// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000088#define CONVERT_SMI_ARG_CHECKED(name, index) \
89 RUNTIME_ASSERT(args[index]->IsSmi()); \
90 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000091
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000092// Cast the given argument to a double and store it in a variable with
93// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000094// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000095#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
96 RUNTIME_ASSERT(args[index]->IsNumber()); \
97 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098
99// Call the specified converter on the object *comand store the result in
100// a variable of the specified type with the given name. If the
101// object is not a Number call IllegalOperation and return.
102#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
103 RUNTIME_ASSERT(obj->IsNumber()); \
104 type name = NumberTo##Type(obj);
105
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000106
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000107MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
108 JSObject* boilerplate) {
109 StackLimitCheck check(isolate);
110 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000111
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000112 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000113 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000114 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000115 if (!maybe_result->ToObject(&result)) return maybe_result;
116 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000117 JSObject* copy = JSObject::cast(result);
118
119 // Deep copy local properties.
120 if (copy->HasFastProperties()) {
121 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000122 for (int i = 0; i < properties->length(); i++) {
123 Object* value = properties->get(i);
124 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000125 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000126 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000127 if (!maybe_result->ToObject(&result)) return maybe_result;
128 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000129 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000130 }
131 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000132 int nof = copy->map()->inobject_properties();
133 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000134 Object* value = copy->InObjectPropertyAt(i);
135 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000136 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000137 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000138 if (!maybe_result->ToObject(&result)) return maybe_result;
139 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000140 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000141 }
142 }
143 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000144 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000145 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000146 if (!maybe_result->ToObject(&result)) return maybe_result;
147 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000148 FixedArray* names = FixedArray::cast(result);
149 copy->GetLocalPropertyNames(names, 0);
150 for (int i = 0; i < names->length(); i++) {
151 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000154 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000155 // Only deep copy fields from the object literal expression.
156 // In particular, don't try to copy the length attribute of
157 // an array.
158 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 Object* value =
160 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000161 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000162 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000163 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000164 if (!maybe_result->ToObject(&result)) return maybe_result;
165 }
166 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000167 // Creating object copy for literals. No strict mode needed.
168 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000169 if (!maybe_result->ToObject(&result)) return maybe_result;
170 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000171 }
172 }
173 }
174
175 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000176 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000177 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000178 switch (copy->GetElementsKind()) {
179 case JSObject::FAST_ELEMENTS: {
180 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000181 if (elements->map() == heap->fixed_cow_array_map()) {
182 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000183#ifdef DEBUG
184 for (int i = 0; i < elements->length(); i++) {
185 ASSERT(!elements->get(i)->IsJSObject());
186 }
187#endif
188 } else {
189 for (int i = 0; i < elements->length(); i++) {
190 Object* value = elements->get(i);
191 if (value->IsJSObject()) {
192 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000193 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
194 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000195 if (!maybe_result->ToObject(&result)) return maybe_result;
196 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000197 elements->set(i, result);
198 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000199 }
200 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000201 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000202 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000203 case JSObject::DICTIONARY_ELEMENTS: {
204 NumberDictionary* element_dictionary = copy->element_dictionary();
205 int capacity = element_dictionary->Capacity();
206 for (int i = 0; i < capacity; i++) {
207 Object* k = element_dictionary->KeyAt(i);
208 if (element_dictionary->IsKey(k)) {
209 Object* value = element_dictionary->ValueAt(i);
210 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000211 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000212 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
213 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000214 if (!maybe_result->ToObject(&result)) return maybe_result;
215 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000216 element_dictionary->ValueAtPut(i, result);
217 }
218 }
219 }
220 break;
221 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000222 case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
223 UNIMPLEMENTED();
224 break;
225 case JSObject::EXTERNAL_PIXEL_ELEMENTS:
226 case JSObject::EXTERNAL_BYTE_ELEMENTS:
227 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
228 case JSObject::EXTERNAL_SHORT_ELEMENTS:
229 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
230 case JSObject::EXTERNAL_INT_ELEMENTS:
231 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
232 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
233 case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
234 case JSObject::FAST_DOUBLE_ELEMENTS:
235 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000236 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000237 }
238 return copy;
239}
240
241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000242RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000243 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000244 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000245}
246
247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000248RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000249 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000250 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000251}
252
253
ager@chromium.org236ad962008-09-25 09:45:57 +0000254static Handle<Map> ComputeObjectLiteralMap(
255 Handle<Context> context,
256 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000257 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000258 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000259 int properties_length = constant_properties->length();
260 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000261 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000262 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000263 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000264 for (int p = 0; p != properties_length; p += 2) {
265 Object* key = constant_properties->get(p);
266 uint32_t element_index = 0;
267 if (key->IsSymbol()) {
268 number_of_symbol_keys++;
269 } else if (key->ToArrayIndex(&element_index)) {
270 // An index key does not require space in the property backing store.
271 number_of_properties--;
272 } else {
273 // Bail out as a non-symbol non-index key makes caching impossible.
274 // ASSERT to make sure that the if condition after the loop is false.
275 ASSERT(number_of_symbol_keys != number_of_properties);
276 break;
277 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000278 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000279 // If we only have symbols and array indices among keys then we can
280 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000281 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000282 if ((number_of_symbol_keys == number_of_properties) &&
283 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000284 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000285 Handle<FixedArray> keys =
286 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000287 if (number_of_symbol_keys > 0) {
288 int index = 0;
289 for (int p = 0; p < properties_length; p += 2) {
290 Object* key = constant_properties->get(p);
291 if (key->IsSymbol()) {
292 keys->set(index++, key);
293 }
294 }
295 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000296 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000297 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000298 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000299 }
300 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000301 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000302 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000303 Handle<Map>(context->object_function()->initial_map()),
304 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000305}
306
307
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000308static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000309 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000310 Handle<FixedArray> literals,
311 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000312
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000313
314static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000315 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000316 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000317 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000318 bool should_have_fast_elements,
319 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000320 // Get the global context from the literals array. This is the
321 // context in which the function was created and we use the object
322 // function from this context to create the object literal. We do
323 // not use the object function from the current global context
324 // because this might be the object function from another context
325 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000326 Handle<Context> context =
327 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
328
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000329 // In case we have function literals, we want the object to be in
330 // slow properties mode for now. We don't go in the map cache because
331 // maps with constant functions can't be shared if the functions are
332 // not the same (which is the common case).
333 bool is_result_from_cache = false;
334 Handle<Map> map = has_function_literal
335 ? Handle<Map>(context->object_function()->initial_map())
336 : ComputeObjectLiteralMap(context,
337 constant_properties,
338 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000339
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000340 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000341
342 // Normalize the elements of the boilerplate to save space if needed.
343 if (!should_have_fast_elements) NormalizeElements(boilerplate);
344
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000345 // Add the constant properties to the boilerplate.
346 int length = constant_properties->length();
347 bool should_transform =
348 !is_result_from_cache && boilerplate->HasFastProperties();
349 if (should_transform || has_function_literal) {
350 // Normalize the properties of object to avoid n^2 behavior
351 // when extending the object multiple properties. Indicate the number of
352 // properties to be added.
353 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
354 }
355
356 for (int index = 0; index < length; index +=2) {
357 Handle<Object> key(constant_properties->get(index+0), isolate);
358 Handle<Object> value(constant_properties->get(index+1), isolate);
359 if (value->IsFixedArray()) {
360 // The value contains the constant_properties of a
361 // simple object or array literal.
362 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
363 value = CreateLiteralBoilerplate(isolate, literals, array);
364 if (value.is_null()) return value;
365 }
366 Handle<Object> result;
367 uint32_t element_index = 0;
368 if (key->IsSymbol()) {
369 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
370 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000371 result = SetOwnElement(boilerplate,
372 element_index,
373 value,
374 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000375 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000376 Handle<String> name(String::cast(*key));
377 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000378 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
379 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000380 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000381 } else if (key->ToArrayIndex(&element_index)) {
382 // Array index (uint32).
383 result = SetOwnElement(boilerplate,
384 element_index,
385 value,
386 kNonStrictMode);
387 } else {
388 // Non-uint32 number.
389 ASSERT(key->IsNumber());
390 double num = key->Number();
391 char arr[100];
392 Vector<char> buffer(arr, ARRAY_SIZE(arr));
393 const char* str = DoubleToCString(num, buffer);
394 Handle<String> name =
395 isolate->factory()->NewStringFromAscii(CStrVector(str));
396 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
397 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000398 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000399 // If setting the property on the boilerplate throws an
400 // exception, the exception is converted to an empty handle in
401 // the handle based operations. In that case, we need to
402 // convert back to an exception.
403 if (result.is_null()) return result;
404 }
405
406 // Transform to fast properties if necessary. For object literals with
407 // containing function literals we defer this operation until after all
408 // computed properties have been assigned so that we can generate
409 // constant function properties.
410 if (should_transform && !has_function_literal) {
411 TransformToFastProperties(boilerplate,
412 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000413 }
414
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000415 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000416}
417
418
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000419static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000420 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000421 Handle<FixedArray> literals,
422 Handle<FixedArray> elements) {
423 // Create the JSArray.
424 Handle<JSFunction> constructor(
425 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000426 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000427
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000428 const bool is_cow =
429 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000430 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000431 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000432
433 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000434 if (is_cow) {
435#ifdef DEBUG
436 // Copy-on-write arrays must be shallow (and simple).
437 for (int i = 0; i < content->length(); i++) {
438 ASSERT(!content->get(i)->IsFixedArray());
439 }
440#endif
441 } else {
442 for (int i = 0; i < content->length(); i++) {
443 if (content->get(i)->IsFixedArray()) {
444 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000445 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000446 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
447 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000448 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000449 if (result.is_null()) return result;
450 content->set(i, *result);
451 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000452 }
453 }
454
455 // Set the elements.
456 Handle<JSArray>::cast(object)->SetContent(*content);
457 return object;
458}
459
460
461static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000462 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000463 Handle<FixedArray> literals,
464 Handle<FixedArray> array) {
465 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000466 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000468 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000469 return CreateObjectLiteralBoilerplate(isolate,
470 literals,
471 elements,
472 true,
473 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000474 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000475 return CreateObjectLiteralBoilerplate(isolate,
476 literals,
477 elements,
478 false,
479 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000480 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000481 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000482 default:
483 UNREACHABLE();
484 return Handle<Object>::null();
485 }
486}
487
488
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000489RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000490 // Takes a FixedArray of elements containing the literal elements of
491 // the array literal and produces JSArray with those elements.
492 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000493 // which contains the context from which to get the Array function
494 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000495 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000496 ASSERT(args.length() == 3);
497 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000498 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000499 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000500
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000501 Handle<Object> object =
502 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000503 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000504
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000505 // Update the functions literal and return the boilerplate.
506 literals->set(literals_index, *object);
507 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000508}
509
510
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000511RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000512 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000513 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000514 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000515 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000516 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000517 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000518 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
519 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000520
521 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000522 Handle<Object> boilerplate(literals->get(literals_index), isolate);
523 if (*boilerplate == isolate->heap()->undefined_value()) {
524 boilerplate = CreateObjectLiteralBoilerplate(isolate,
525 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000526 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000527 should_have_fast_elements,
528 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000529 if (boilerplate.is_null()) return Failure::Exception();
530 // Update the functions literal and return the boilerplate.
531 literals->set(literals_index, *boilerplate);
532 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000533 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000534}
535
536
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000537RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000538 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000539 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000540 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000541 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000542 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000543 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000544 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
545 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000546
547 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000548 Handle<Object> boilerplate(literals->get(literals_index), isolate);
549 if (*boilerplate == isolate->heap()->undefined_value()) {
550 boilerplate = CreateObjectLiteralBoilerplate(isolate,
551 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000552 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000553 should_have_fast_elements,
554 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000555 if (boilerplate.is_null()) return Failure::Exception();
556 // Update the functions literal and return the boilerplate.
557 literals->set(literals_index, *boilerplate);
558 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000559 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000560}
561
562
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000563RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000564 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000565 ASSERT(args.length() == 3);
566 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000567 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000568 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
569
570 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000571 Handle<Object> boilerplate(literals->get(literals_index), isolate);
572 if (*boilerplate == isolate->heap()->undefined_value()) {
573 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000574 if (boilerplate.is_null()) return Failure::Exception();
575 // Update the functions literal and return the boilerplate.
576 literals->set(literals_index, *boilerplate);
577 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000578 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000579}
580
581
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000582RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000583 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000584 ASSERT(args.length() == 3);
585 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000586 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000587 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
588
589 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000590 Handle<Object> boilerplate(literals->get(literals_index), isolate);
591 if (*boilerplate == isolate->heap()->undefined_value()) {
592 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000593 if (boilerplate.is_null()) return Failure::Exception();
594 // Update the functions literal and return the boilerplate.
595 literals->set(literals_index, *boilerplate);
596 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000597 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000598 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000599 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000600 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000601 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000602}
603
604
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000605RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
606 ASSERT(args.length() == 2);
607 Object* handler = args[0];
608 Object* prototype = args[1];
609 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000610 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000611 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
612}
613
614
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000615RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
616 ASSERT(args.length() == 1);
617 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000618 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000619}
620
621
622RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
623 ASSERT(args.length() == 1);
624 CONVERT_CHECKED(JSProxy, proxy, args[0]);
625 return proxy->handler();
626}
627
628
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000629RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
630 ASSERT(args.length() == 1);
631 CONVERT_CHECKED(JSProxy, proxy, args[0]);
632 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000633 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000634}
635
636
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000637RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
638 HandleScope scope(isolate);
639 ASSERT(args.length() == 1);
640 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
641 ASSERT(weakmap->map()->inobject_properties() == 0);
642 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
643 weakmap->set_table(*table);
644 weakmap->set_next(Smi::FromInt(0));
645 return *weakmap;
646}
647
648
649RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
650 NoHandleAllocation ha;
651 ASSERT(args.length() == 2);
652 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
653 // TODO(mstarzinger): Currently we cannot use JSProxy objects as keys
654 // because they cannot be cast to JSObject to get an identity hash code.
655 CONVERT_ARG_CHECKED(JSObject, key, 1);
656 return weakmap->table()->Lookup(*key);
657}
658
659
660RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
661 HandleScope scope(isolate);
662 ASSERT(args.length() == 3);
663 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
664 // TODO(mstarzinger): See Runtime_WeakMapGet above.
665 CONVERT_ARG_CHECKED(JSObject, key, 1);
666 Handle<Object> value(args[2]);
667 Handle<ObjectHashTable> table(weakmap->table());
668 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
669 weakmap->set_table(*new_table);
670 return *value;
671}
672
673
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000674RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000675 NoHandleAllocation ha;
676 ASSERT(args.length() == 1);
677 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000678 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000679 return JSObject::cast(obj)->class_name();
680}
681
ager@chromium.org7c537e22008-10-16 08:43:32 +0000682
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000683RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
684 NoHandleAllocation ha;
685 ASSERT(args.length() == 1);
686 Object* obj = args[0];
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000687 do {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000688 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000689 } while (obj->IsJSObject() &&
690 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000691 return obj;
692}
693
694
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000695RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696 NoHandleAllocation ha;
697 ASSERT(args.length() == 2);
698 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
699 Object* O = args[0];
700 Object* V = args[1];
701 while (true) {
702 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000703 if (prototype->IsNull()) return isolate->heap()->false_value();
704 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000705 V = prototype;
706 }
707}
708
709
ager@chromium.org9085a012009-05-11 19:22:57 +0000710// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000711RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000712 NoHandleAllocation ha;
713 ASSERT(args.length() == 2);
714 CONVERT_CHECKED(JSObject, jsobject, args[0]);
715 CONVERT_CHECKED(JSObject, proto, args[1]);
716
717 // Sanity checks. The old prototype (that we are replacing) could
718 // theoretically be null, but if it is not null then check that we
719 // didn't already install a hidden prototype here.
720 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
721 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
722 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
723
724 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000725 Object* map_or_failure;
726 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
727 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
728 return maybe_map_or_failure;
729 }
730 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000731 Map* new_proto_map = Map::cast(map_or_failure);
732
lrn@chromium.org303ada72010-10-27 09:33:13 +0000733 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
734 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
735 return maybe_map_or_failure;
736 }
737 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000738 Map* new_map = Map::cast(map_or_failure);
739
740 // Set proto's prototype to be the old prototype of the object.
741 new_proto_map->set_prototype(jsobject->GetPrototype());
742 proto->set_map(new_proto_map);
743 new_proto_map->set_is_hidden_prototype();
744
745 // Set the object's prototype to proto.
746 new_map->set_prototype(proto);
747 jsobject->set_map(new_map);
748
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000749 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000750}
751
752
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000753RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000754 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000755 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000756 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000757 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000758}
759
760
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000761// Recursively traverses hidden prototypes if property is not found
762static void GetOwnPropertyImplementation(JSObject* obj,
763 String* name,
764 LookupResult* result) {
765 obj->LocalLookupRealNamedProperty(name, result);
766
767 if (!result->IsProperty()) {
768 Object* proto = obj->GetPrototype();
769 if (proto->IsJSObject() &&
770 JSObject::cast(proto)->map()->is_hidden_prototype())
771 GetOwnPropertyImplementation(JSObject::cast(proto),
772 name, result);
773 }
774}
775
776
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000777static bool CheckAccessException(LookupResult* result,
778 v8::AccessType access_type) {
779 if (result->type() == CALLBACKS) {
780 Object* callback = result->GetCallbackObject();
781 if (callback->IsAccessorInfo()) {
782 AccessorInfo* info = AccessorInfo::cast(callback);
783 bool can_access =
784 (access_type == v8::ACCESS_HAS &&
785 (info->all_can_read() || info->all_can_write())) ||
786 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
787 (access_type == v8::ACCESS_SET && info->all_can_write());
788 return can_access;
789 }
790 }
791
792 return false;
793}
794
795
796static bool CheckAccess(JSObject* obj,
797 String* name,
798 LookupResult* result,
799 v8::AccessType access_type) {
800 ASSERT(result->IsProperty());
801
802 JSObject* holder = result->holder();
803 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000804 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000805 while (true) {
806 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000807 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000808 // Access check callback denied the access, but some properties
809 // can have a special permissions which override callbacks descision
810 // (currently see v8::AccessControl).
811 break;
812 }
813
814 if (current == holder) {
815 return true;
816 }
817
818 current = JSObject::cast(current->GetPrototype());
819 }
820
821 // API callbacks can have per callback access exceptions.
822 switch (result->type()) {
823 case CALLBACKS: {
824 if (CheckAccessException(result, access_type)) {
825 return true;
826 }
827 break;
828 }
829 case INTERCEPTOR: {
830 // If the object has an interceptor, try real named properties.
831 // Overwrite the result to fetch the correct property later.
832 holder->LookupRealNamedProperty(name, result);
833 if (result->IsProperty()) {
834 if (CheckAccessException(result, access_type)) {
835 return true;
836 }
837 }
838 break;
839 }
840 default:
841 break;
842 }
843
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000844 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000845 return false;
846}
847
848
849// TODO(1095): we should traverse hidden prototype hierachy as well.
850static bool CheckElementAccess(JSObject* obj,
851 uint32_t index,
852 v8::AccessType access_type) {
853 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000854 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000855 return false;
856 }
857
858 return true;
859}
860
861
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000862// Enumerator used as indices into the array returned from GetOwnProperty
863enum PropertyDescriptorIndices {
864 IS_ACCESSOR_INDEX,
865 VALUE_INDEX,
866 GETTER_INDEX,
867 SETTER_INDEX,
868 WRITABLE_INDEX,
869 ENUMERABLE_INDEX,
870 CONFIGURABLE_INDEX,
871 DESCRIPTOR_SIZE
872};
873
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000874// Returns an array with the property description:
875// if args[1] is not a property on args[0]
876// returns undefined
877// if args[1] is a data property on args[0]
878// [false, value, Writeable, Enumerable, Configurable]
879// if args[1] is an accessor on args[0]
880// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000881RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000882 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000883 Heap* heap = isolate->heap();
884 HandleScope scope(isolate);
885 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
886 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000887 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000888 CONVERT_ARG_CHECKED(JSObject, obj, 0);
889 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000890
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000891 // This could be an element.
892 uint32_t index;
893 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000894 switch (obj->HasLocalElement(index)) {
895 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000896 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000897
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000898 case JSObject::STRING_CHARACTER_ELEMENT: {
899 // Special handling of string objects according to ECMAScript 5
900 // 15.5.5.2. Note that this might be a string object with elements
901 // other than the actual string value. This is covered by the
902 // subsequent cases.
903 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
904 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000905 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000906
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000907 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000908 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000909 elms->set(WRITABLE_INDEX, heap->false_value());
910 elms->set(ENUMERABLE_INDEX, heap->false_value());
911 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000912 return *desc;
913 }
914
915 case JSObject::INTERCEPTED_ELEMENT:
916 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000917 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000918 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000919 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000920 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000921 elms->set(WRITABLE_INDEX, heap->true_value());
922 elms->set(ENUMERABLE_INDEX, heap->true_value());
923 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000924 return *desc;
925 }
926
927 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000928 Handle<JSObject> holder = obj;
929 if (obj->IsJSGlobalProxy()) {
930 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000931 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000932 ASSERT(proto->IsJSGlobalObject());
933 holder = Handle<JSObject>(JSObject::cast(proto));
934 }
whesse@chromium.org7b260152011-06-20 15:33:18 +0000935 FixedArray* elements = FixedArray::cast(holder->elements());
936 NumberDictionary* dictionary = NULL;
937 if (elements->map() == heap->non_strict_arguments_elements_map()) {
938 dictionary = NumberDictionary::cast(elements->get(1));
939 } else {
940 dictionary = NumberDictionary::cast(elements);
941 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000942 int entry = dictionary->FindEntry(index);
943 ASSERT(entry != NumberDictionary::kNotFound);
944 PropertyDetails details = dictionary->DetailsAt(entry);
945 switch (details.type()) {
946 case CALLBACKS: {
947 // This is an accessor property with getter and/or setter.
948 FixedArray* callbacks =
949 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000950 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000951 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
952 elms->set(GETTER_INDEX, callbacks->get(0));
953 }
954 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
955 elms->set(SETTER_INDEX, callbacks->get(1));
956 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000957 break;
958 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000959 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000960 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000961 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000962 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000963 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000964 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000965 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000966 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000967 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000968 default:
969 UNREACHABLE();
970 break;
971 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000972 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
973 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000974 return *desc;
975 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000976 }
977 }
978
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000979 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000980 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000981
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000982 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000983 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000984 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000985
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000986 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000987 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000988 }
989
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000990 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
991 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000992
993 bool is_js_accessor = (result.type() == CALLBACKS) &&
994 (result.GetCallbackObject()->IsFixedArray());
995
996 if (is_js_accessor) {
997 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000998 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000999
1000 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
1001 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1002 elms->set(GETTER_INDEX, structure->get(0));
1003 }
1004 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1005 elms->set(SETTER_INDEX, structure->get(1));
1006 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001007 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001008 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1009 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001010
1011 PropertyAttributes attrs;
1012 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001013 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001014 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1015 if (!maybe_value->ToObject(&value)) return maybe_value;
1016 }
1017 elms->set(VALUE_INDEX, value);
1018 }
1019
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001020 return *desc;
1021}
1022
1023
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001024RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001025 ASSERT(args.length() == 1);
1026 CONVERT_CHECKED(JSObject, obj, args[0]);
1027 return obj->PreventExtensions();
1028}
1029
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001030
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001031RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001032 ASSERT(args.length() == 1);
1033 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001034 if (obj->IsJSGlobalProxy()) {
1035 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001036 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001037 ASSERT(proto->IsJSGlobalObject());
1038 obj = JSObject::cast(proto);
1039 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001040 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001041}
1042
1043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001044RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001045 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001046 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001047 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1048 CONVERT_ARG_CHECKED(String, pattern, 1);
1049 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001050 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1051 if (result.is_null()) return Failure::Exception();
1052 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001053}
1054
1055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001056RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001057 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001058 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001059 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001060 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001061}
1062
1063
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001064RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001065 ASSERT(args.length() == 1);
1066 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001067 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001068 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001069}
1070
1071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001072RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001073 ASSERT(args.length() == 2);
1074 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001075 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001076 int index = field->value();
1077 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1078 InstanceType type = templ->map()->instance_type();
1079 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1080 type == OBJECT_TEMPLATE_INFO_TYPE);
1081 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001082 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001083 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1084 } else {
1085 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1086 }
1087 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001088}
1089
1090
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001091RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001092 ASSERT(args.length() == 1);
1093 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001094 Map* old_map = object->map();
1095 bool needs_access_checks = old_map->is_access_check_needed();
1096 if (needs_access_checks) {
1097 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001098 Object* new_map;
1099 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1100 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1101 }
ager@chromium.org32912102009-01-16 10:38:43 +00001102
1103 Map::cast(new_map)->set_is_access_check_needed(false);
1104 object->set_map(Map::cast(new_map));
1105 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001106 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001107}
1108
1109
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001110RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001111 ASSERT(args.length() == 1);
1112 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001113 Map* old_map = object->map();
1114 if (!old_map->is_access_check_needed()) {
1115 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001116 Object* new_map;
1117 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1118 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1119 }
ager@chromium.org32912102009-01-16 10:38:43 +00001120
1121 Map::cast(new_map)->set_is_access_check_needed(true);
1122 object->set_map(Map::cast(new_map));
1123 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001124 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001125}
1126
1127
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001128static Failure* ThrowRedeclarationError(Isolate* isolate,
1129 const char* type,
1130 Handle<String> name) {
1131 HandleScope scope(isolate);
1132 Handle<Object> type_handle =
1133 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001134 Handle<Object> args[2] = { type_handle, name };
1135 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001136 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1137 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001138}
1139
1140
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001141RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001142 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001143 HandleScope scope(isolate);
1144 Handle<GlobalObject> global = Handle<GlobalObject>(
1145 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001146
ager@chromium.org3811b432009-10-28 14:53:37 +00001147 Handle<Context> context = args.at<Context>(0);
1148 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001149 bool is_eval = args.smi_at(2) == 1;
1150 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001151 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001152
1153 // Compute the property attributes. According to ECMA-262, section
1154 // 13, page 71, the property must be read-only and
1155 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1156 // property as read-only, so we don't either.
1157 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1158
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001159 // Traverse the name/value pairs and set the properties.
1160 int length = pairs->length();
1161 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001162 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001163 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001164 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001165
1166 // We have to declare a global const property. To capture we only
1167 // assign to it when evaluating the assignment for "const x =
1168 // <expr>" the initial value is the hole.
1169 bool is_const_property = value->IsTheHole();
1170
1171 if (value->IsUndefined() || is_const_property) {
1172 // Lookup the property in the global object, and don't set the
1173 // value of the variable if the property is already there.
1174 LookupResult lookup;
1175 global->Lookup(*name, &lookup);
1176 if (lookup.IsProperty()) {
1177 // Determine if the property is local by comparing the holder
1178 // against the global object. The information will be used to
1179 // avoid throwing re-declaration errors when declaring
1180 // variables or constants that exist in the prototype chain.
1181 bool is_local = (*global == lookup.holder());
1182 // Get the property attributes and determine if the property is
1183 // read-only.
1184 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1185 bool is_read_only = (attributes & READ_ONLY) != 0;
1186 if (lookup.type() == INTERCEPTOR) {
1187 // If the interceptor says the property is there, we
1188 // just return undefined without overwriting the property.
1189 // Otherwise, we continue to setting the property.
1190 if (attributes != ABSENT) {
1191 // Check if the existing property conflicts with regards to const.
1192 if (is_local && (is_read_only || is_const_property)) {
1193 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001194 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001195 };
1196 // The property already exists without conflicting: Go to
1197 // the next declaration.
1198 continue;
1199 }
1200 // Fall-through and introduce the absent property by using
1201 // SetProperty.
1202 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001203 // For const properties, we treat a callback with this name
1204 // even in the prototype as a conflicting declaration.
1205 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001206 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001207 }
1208 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001209 if (is_local && (is_read_only || is_const_property)) {
1210 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001211 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001212 }
1213 // The property already exists without conflicting: Go to
1214 // the next declaration.
1215 continue;
1216 }
1217 }
1218 } else {
1219 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001220 Handle<SharedFunctionInfo> shared =
1221 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001222 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001223 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1224 context,
1225 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226 value = function;
1227 }
1228
1229 LookupResult lookup;
1230 global->LocalLookup(*name, &lookup);
1231
1232 PropertyAttributes attributes = is_const_property
1233 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1234 : base;
1235
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001236 // There's a local property that we need to overwrite because
1237 // we're either declaring a function or there's an interceptor
1238 // that claims the property is absent.
1239 //
1240 // Check for conflicting re-declarations. We cannot have
1241 // conflicting types in case of intercepted properties because
1242 // they are absent.
1243 if (lookup.IsProperty() &&
1244 (lookup.type() != INTERCEPTOR) &&
1245 (lookup.IsReadOnly() || is_const_property)) {
1246 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001247 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001248 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001250 // Safari does not allow the invocation of callback setters for
1251 // function declarations. To mimic this behavior, we do not allow
1252 // the invocation of setters for function values. This makes a
1253 // difference for global functions with the same names as event
1254 // handlers such as "function onload() {}". Firefox does call the
1255 // onload setter in those case and Safari does not. We follow
1256 // Safari for compatibility.
1257 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001258 // Do not change DONT_DELETE to false from true.
1259 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1260 attributes = static_cast<PropertyAttributes>(
1261 attributes | (lookup.GetAttributes() & DONT_DELETE));
1262 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001263 RETURN_IF_EMPTY_HANDLE(isolate,
1264 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001265 name,
1266 value,
1267 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001268 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001269 RETURN_IF_EMPTY_HANDLE(isolate,
1270 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001271 name,
1272 value,
1273 attributes,
1274 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001275 }
1276 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001277
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001278 ASSERT(!isolate->has_pending_exception());
1279 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001280}
1281
1282
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001283RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001284 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001285 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286
ager@chromium.org7c537e22008-10-16 08:43:32 +00001287 CONVERT_ARG_CHECKED(Context, context, 0);
1288 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001289 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001290 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001291 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001292
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001293 // Declarations are always done in a function or global context.
1294 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001295
1296 int index;
1297 PropertyAttributes attributes;
1298 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001299 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001300 context->Lookup(name, flags, &index, &attributes);
1301
1302 if (attributes != ABSENT) {
1303 // The name was declared before; check for conflicting
1304 // re-declarations: This is similar to the code in parser.cc in
1305 // the AstBuildingParser::Declare function.
1306 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1307 // Functions are not read-only.
1308 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1309 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001310 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311 }
1312
1313 // Initialize it if necessary.
1314 if (*initial_value != NULL) {
1315 if (index >= 0) {
1316 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001317 // the function context or the arguments object.
1318 if (holder->IsContext()) {
1319 ASSERT(holder.is_identical_to(context));
1320 if (((attributes & READ_ONLY) == 0) ||
1321 context->get(index)->IsTheHole()) {
1322 context->set(index, *initial_value);
1323 }
1324 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001325 // The holder is an arguments object.
1326 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001327 Handle<Object> result = SetElement(arguments, index, initial_value,
1328 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001329 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001330 }
1331 } else {
1332 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001333 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001334 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001335 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001336 SetProperty(context_ext, name, initial_value,
1337 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338 }
1339 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001340
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001341 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001342 // The property is not in the function context. It needs to be
1343 // "declared" in the function context's extension context, or in the
1344 // global context.
1345 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001346 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001347 // The function context's extension context exists - use it.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001348 context_ext = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001349 } else {
1350 // The function context's extension context does not exists - allocate
1351 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001352 context_ext = isolate->factory()->NewJSObject(
1353 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001354 // And store it in the extension slot.
1355 context->set_extension(*context_ext);
1356 }
1357 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358
ager@chromium.org7c537e22008-10-16 08:43:32 +00001359 // Declare the property by setting it to the initial value if provided,
1360 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1361 // constant declarations).
1362 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001363 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001364 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001365 // Declaring a const context slot is a conflicting declaration if
1366 // there is a callback with that name in a prototype. It is
1367 // allowed to introduce const variables in
1368 // JSContextExtensionObjects. They are treated specially in
1369 // SetProperty and no setters are invoked for those since they are
1370 // not real JSObjects.
1371 if (initial_value->IsTheHole() &&
1372 !context_ext->IsJSContextExtensionObject()) {
1373 LookupResult lookup;
1374 context_ext->Lookup(*name, &lookup);
1375 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001376 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001377 }
1378 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001379 RETURN_IF_EMPTY_HANDLE(isolate,
1380 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001381 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001382 }
1383
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001384 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001385}
1386
1387
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001388RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001389 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001390 // args[0] == name
1391 // args[1] == strict_mode
1392 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001393
1394 // Determine if we need to assign to the variable if it already
1395 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001396 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1397 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001398
1399 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001400 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001401 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001402 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001403 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001404
1405 // According to ECMA-262, section 12.2, page 62, the property must
1406 // not be deletable.
1407 PropertyAttributes attributes = DONT_DELETE;
1408
1409 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001410 // there, there is a property with this name in the prototype chain.
1411 // We follow Safari and Firefox behavior and only set the property
1412 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001413 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001414 // Note that objects can have hidden prototypes, so we need to traverse
1415 // the whole chain of hidden prototypes to do a 'local' lookup.
1416 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001417 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001418 while (true) {
1419 real_holder->LocalLookup(*name, &lookup);
1420 if (lookup.IsProperty()) {
1421 // Determine if this is a redeclaration of something read-only.
1422 if (lookup.IsReadOnly()) {
1423 // If we found readonly property on one of hidden prototypes,
1424 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001425 if (real_holder != isolate->context()->global()) break;
1426 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001427 }
1428
1429 // Determine if this is a redeclaration of an intercepted read-only
1430 // property and figure out if the property exists at all.
1431 bool found = true;
1432 PropertyType type = lookup.type();
1433 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001434 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001435 Handle<JSObject> holder(real_holder);
1436 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1437 real_holder = *holder;
1438 if (intercepted == ABSENT) {
1439 // The interceptor claims the property isn't there. We need to
1440 // make sure to introduce it.
1441 found = false;
1442 } else if ((intercepted & READ_ONLY) != 0) {
1443 // The property is present, but read-only. Since we're trying to
1444 // overwrite it with a variable declaration we must throw a
1445 // re-declaration error. However if we found readonly property
1446 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001447 if (real_holder != isolate->context()->global()) break;
1448 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001449 }
1450 }
1451
1452 if (found && !assign) {
1453 // The global property is there and we're not assigning any value
1454 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001455 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001456 }
1457
1458 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001459 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001460 return real_holder->SetProperty(
1461 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001462 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001463
1464 Object* proto = real_holder->GetPrototype();
1465 if (!proto->IsJSObject())
1466 break;
1467
1468 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1469 break;
1470
1471 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472 }
1473
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001474 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001475 if (assign) {
1476 return global->SetProperty(*name, args[2], attributes, strict_mode);
1477 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001478 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001479}
1480
1481
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001482RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001483 // All constants are declared with an initial value. The name
1484 // of the constant is the first argument and the initial value
1485 // is the second.
1486 RUNTIME_ASSERT(args.length() == 2);
1487 CONVERT_ARG_CHECKED(String, name, 0);
1488 Handle<Object> value = args.at<Object>(1);
1489
1490 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001491 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001492
1493 // According to ECMA-262, section 12.2, page 62, the property must
1494 // not be deletable. Since it's a const, it must be READ_ONLY too.
1495 PropertyAttributes attributes =
1496 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1497
1498 // Lookup the property locally in the global object. If it isn't
1499 // there, we add the property and take special precautions to always
1500 // add it as a local property even in case of callbacks in the
1501 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001502 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001503 LookupResult lookup;
1504 global->LocalLookup(*name, &lookup);
1505 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001506 return global->SetLocalPropertyIgnoreAttributes(*name,
1507 *value,
1508 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001509 }
1510
1511 // Determine if this is a redeclaration of something not
1512 // read-only. In case the result is hidden behind an interceptor we
1513 // need to ask it for the property attributes.
1514 if (!lookup.IsReadOnly()) {
1515 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001516 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001517 }
1518
1519 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1520
1521 // Throw re-declaration error if the intercepted property is present
1522 // but not read-only.
1523 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001524 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001525 }
1526
1527 // Restore global object from context (in case of GC) and continue
1528 // with setting the value because the property is either absent or
1529 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001530 HandleScope handle_scope(isolate);
1531 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001532
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001533 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001534 // property through an interceptor and only do it if it's
1535 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001536 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001537 RETURN_IF_EMPTY_HANDLE(isolate,
1538 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001539 name,
1540 value,
1541 attributes,
1542 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 return *value;
1544 }
1545
1546 // Set the value, but only we're assigning the initial value to a
1547 // constant. For now, we determine this by checking if the
1548 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001549 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001550 PropertyType type = lookup.type();
1551 if (type == FIELD) {
1552 FixedArray* properties = global->properties();
1553 int index = lookup.GetFieldIndex();
1554 if (properties->get(index)->IsTheHole()) {
1555 properties->set(index, *value);
1556 }
1557 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001558 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1559 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560 }
1561 } else {
1562 // Ignore re-initialization of constants that have already been
1563 // assigned a function value.
1564 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1565 }
1566
1567 // Use the set value as the result of the operation.
1568 return *value;
1569}
1570
1571
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001572RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001573 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001574 ASSERT(args.length() == 3);
1575
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001576 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001577 ASSERT(!value->IsTheHole());
1578 CONVERT_ARG_CHECKED(Context, context, 1);
1579 Handle<String> name(String::cast(args[2]));
1580
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001581 // Initializations are always done in a function or global context.
1582 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001583
1584 int index;
1585 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001586 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001587 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001588 context->Lookup(name, flags, &index, &attributes);
1589
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001590 // In most situations, the property introduced by the const
1591 // declaration should be present in the context extension object.
1592 // However, because declaration and initialization are separate, the
1593 // property might have been deleted (if it was introduced by eval)
1594 // before we reach the initialization point.
1595 //
1596 // Example:
1597 //
1598 // function f() { eval("delete x; const x;"); }
1599 //
1600 // In that case, the initialization behaves like a normal assignment
1601 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001603 if (holder->IsContext()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001604 // Property was found in a context. Perform the assignment if we
1605 // found some non-constant or an uninitialized constant.
1606 Handle<Context> context = Handle<Context>::cast(holder);
1607 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1608 context->set(index, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001609 }
1610 } else {
1611 // The holder is an arguments object.
1612 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001613 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001614 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001615 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001616 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001617 }
1618 return *value;
1619 }
1620
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001621 // The property could not be found, we introduce it in the global
1622 // context.
1623 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001624 Handle<JSObject> global = Handle<JSObject>(
1625 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001626 // Strict mode not needed (const disallowed in strict mode).
1627 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001628 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001629 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001630 return *value;
1631 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001632
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001633 // The property was present in a context extension object.
1634 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001635
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001636 if (*context_ext == context->extension()) {
1637 // This is the property that was introduced by the const
1638 // declaration. Set it if it hasn't been set before. NOTE: We
1639 // cannot use GetProperty() to get the current value as it
1640 // 'unholes' the value.
1641 LookupResult lookup;
1642 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1643 ASSERT(lookup.IsProperty()); // the property was declared
1644 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1645
1646 PropertyType type = lookup.type();
1647 if (type == FIELD) {
1648 FixedArray* properties = context_ext->properties();
1649 int index = lookup.GetFieldIndex();
1650 if (properties->get(index)->IsTheHole()) {
1651 properties->set(index, *value);
1652 }
1653 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001654 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1655 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001656 }
1657 } else {
1658 // We should not reach here. Any real, named property should be
1659 // either a field or a dictionary slot.
1660 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001661 }
1662 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001663 // The property was found in a different context extension object.
1664 // Set it if it is not a read-only property.
1665 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001666 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001667 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001668 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001669 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001670 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001671 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001672
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001673 return *value;
1674}
1675
1676
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001677RUNTIME_FUNCTION(MaybeObject*,
1678 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001679 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001680 ASSERT(args.length() == 2);
1681 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001682 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001683 if (object->HasFastProperties()) {
1684 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1685 }
1686 return *object;
1687}
1688
1689
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001690RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001691 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001692 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001693 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1694 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001695 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001696 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001697 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001698 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001699 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001700 RUNTIME_ASSERT(index >= 0);
1701 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001702 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001703 Handle<Object> result = RegExpImpl::Exec(regexp,
1704 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001705 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001706 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001707 if (result.is_null()) return Failure::Exception();
1708 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001709}
1710
1711
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001712RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001713 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001714 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001715 if (elements_count < 0 ||
1716 elements_count > FixedArray::kMaxLength ||
1717 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001718 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001719 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001720 Object* new_object;
1721 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001722 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001723 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1724 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001725 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001726 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1727 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001728 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1729 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001730 {
1731 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001732 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001733 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001734 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001735 }
1736 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001737 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001738 array->set_elements(elements);
1739 array->set_length(Smi::FromInt(elements_count));
1740 // Write in-object properties after the length of the array.
1741 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1742 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1743 return array;
1744}
1745
1746
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001747RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001748 AssertNoAllocation no_alloc;
1749 ASSERT(args.length() == 5);
1750 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1751 CONVERT_CHECKED(String, source, args[1]);
1752
1753 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001754 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001755
1756 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001757 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001758
1759 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001760 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001761
1762 Map* map = regexp->map();
1763 Object* constructor = map->constructor();
1764 if (constructor->IsJSFunction() &&
1765 JSFunction::cast(constructor)->initial_map() == map) {
1766 // If we still have the original map, set in-object properties directly.
1767 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1768 // TODO(lrn): Consider skipping write barrier on booleans as well.
1769 // Both true and false should be in oldspace at all times.
1770 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1771 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1772 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1773 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1774 Smi::FromInt(0),
1775 SKIP_WRITE_BARRIER);
1776 return regexp;
1777 }
1778
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001779 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001780 PropertyAttributes final =
1781 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1782 PropertyAttributes writable =
1783 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001784 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001785 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001786 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001787 source,
1788 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001789 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001790 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001791 global,
1792 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001793 ASSERT(!result->IsFailure());
1794 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001795 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001796 ignoreCase,
1797 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001798 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001799 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001800 multiline,
1801 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001802 ASSERT(!result->IsFailure());
1803 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001804 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001805 Smi::FromInt(0),
1806 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001807 ASSERT(!result->IsFailure());
1808 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001809 return regexp;
1810}
1811
1812
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001813RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001814 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001815 ASSERT(args.length() == 1);
1816 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1817 // This is necessary to enable fast checks for absence of elements
1818 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001819 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001820 return Smi::FromInt(0);
1821}
1822
1823
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001824static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1825 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001826 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001827 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001828 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1829 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1830 Handle<JSFunction> optimized =
1831 isolate->factory()->NewFunction(key,
1832 JS_OBJECT_TYPE,
1833 JSObject::kHeaderSize,
1834 code,
1835 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001836 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001837 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001838 return optimized;
1839}
1840
1841
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001842RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001843 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001844 ASSERT(args.length() == 1);
1845 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1846
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001847 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1848 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1849 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1850 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1851 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1852 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1853 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001854
1855 return *holder;
1856}
1857
1858
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001859RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001860 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001861 Context* global_context =
1862 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001863 return global_context->global()->global_receiver();
1864}
1865
1866
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001867RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001868 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001869 ASSERT(args.length() == 4);
1870 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001871 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001872 Handle<String> pattern = args.at<String>(2);
1873 Handle<String> flags = args.at<String>(3);
1874
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001875 // Get the RegExp function from the context in the literals array.
1876 // This is the RegExp function from the context in which the
1877 // function was created. We do not use the RegExp function from the
1878 // current global context because this might be the RegExp function
1879 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001880 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001881 Handle<JSFunction>(
1882 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001883 // Compute the regular expression literal.
1884 bool has_pending_exception;
1885 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001886 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1887 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001888 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001889 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001890 return Failure::Exception();
1891 }
1892 literals->set(index, *regexp);
1893 return *regexp;
1894}
1895
1896
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001897RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001898 NoHandleAllocation ha;
1899 ASSERT(args.length() == 1);
1900
1901 CONVERT_CHECKED(JSFunction, f, args[0]);
1902 return f->shared()->name();
1903}
1904
1905
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001906RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001907 NoHandleAllocation ha;
1908 ASSERT(args.length() == 2);
1909
1910 CONVERT_CHECKED(JSFunction, f, args[0]);
1911 CONVERT_CHECKED(String, name, args[1]);
1912 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001913 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001914}
1915
1916
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001917RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1918 NoHandleAllocation ha;
1919 ASSERT(args.length() == 1);
1920 CONVERT_CHECKED(JSFunction, f, args[0]);
1921 return isolate->heap()->ToBoolean(
1922 f->shared()->name_should_print_as_anonymous());
1923}
1924
1925
1926RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1927 NoHandleAllocation ha;
1928 ASSERT(args.length() == 1);
1929 CONVERT_CHECKED(JSFunction, f, args[0]);
1930 f->shared()->set_name_should_print_as_anonymous(true);
1931 return isolate->heap()->undefined_value();
1932}
1933
1934
whesse@chromium.org7b260152011-06-20 15:33:18 +00001935RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1936 HandleScope scope(isolate);
1937 ASSERT(args.length() == 1);
1938
1939 CONVERT_CHECKED(JSFunction, fun, args[0]);
1940 fun->shared()->set_bound(true);
1941 return isolate->heap()->undefined_value();
1942}
1943
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001944RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001945 NoHandleAllocation ha;
1946 ASSERT(args.length() == 1);
1947
1948 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001949 Object* obj = f->RemovePrototype();
1950 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001951
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001952 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001953}
1954
1955
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001956RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001957 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001958 ASSERT(args.length() == 1);
1959
1960 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001961 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1962 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001963
1964 return *GetScriptWrapper(Handle<Script>::cast(script));
1965}
1966
1967
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001968RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001969 NoHandleAllocation ha;
1970 ASSERT(args.length() == 1);
1971
1972 CONVERT_CHECKED(JSFunction, f, args[0]);
1973 return f->shared()->GetSourceCode();
1974}
1975
1976
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001977RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001978 NoHandleAllocation ha;
1979 ASSERT(args.length() == 1);
1980
1981 CONVERT_CHECKED(JSFunction, fun, args[0]);
1982 int pos = fun->shared()->start_position();
1983 return Smi::FromInt(pos);
1984}
1985
1986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001987RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001988 ASSERT(args.length() == 2);
1989
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001990 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001991 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1992
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001993 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1994
1995 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001996 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001997}
1998
1999
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002000RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002001 NoHandleAllocation ha;
2002 ASSERT(args.length() == 2);
2003
2004 CONVERT_CHECKED(JSFunction, fun, args[0]);
2005 CONVERT_CHECKED(String, name, args[1]);
2006 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002007 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002008}
2009
2010
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002011RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002012 NoHandleAllocation ha;
2013 ASSERT(args.length() == 2);
2014
2015 CONVERT_CHECKED(JSFunction, fun, args[0]);
2016 CONVERT_CHECKED(Smi, length, args[1]);
2017 fun->shared()->set_length(length->value());
2018 return length;
2019}
2020
2021
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002022// Creates a local, readonly, property called length with the correct
2023// length (when read by the user). This effectively overwrites the
2024// interceptor used to normally provide the length.
2025RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionSetLength) {
2026 NoHandleAllocation ha;
2027 ASSERT(args.length() == 2);
2028 CONVERT_CHECKED(JSFunction, fun, args[0]);
2029 CONVERT_CHECKED(Smi, length, args[1]);
2030 MaybeObject* maybe_name =
2031 isolate->heap()->AllocateStringFromAscii(CStrVector("length"));
2032 String* name;
2033 if (!maybe_name->To(&name)) return maybe_name;
2034 PropertyAttributes attr =
2035 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
2036 return fun->AddProperty(name, length, attr, kNonStrictMode);
2037}
2038
2039
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002040RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002041 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002042 ASSERT(args.length() == 2);
2043
2044 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002045 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002046 Object* obj;
2047 { MaybeObject* maybe_obj =
2048 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2049 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2050 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002051 return args[0]; // return TOS
2052}
2053
2054
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002055RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2056 NoHandleAllocation ha;
2057 RUNTIME_ASSERT(args.length() == 1);
2058 CONVERT_CHECKED(JSFunction, function, args[0]);
2059
2060 MaybeObject* maybe_name =
2061 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2062 String* name;
2063 if (!maybe_name->To(&name)) return maybe_name;
2064
2065 if (function->HasFastProperties()) {
2066 // Construct a new field descriptor with updated attributes.
2067 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2068 int index = instance_desc->Search(name);
2069 ASSERT(index != DescriptorArray::kNotFound);
2070 PropertyDetails details(instance_desc->GetDetails(index));
2071 CallbacksDescriptor new_desc(name,
2072 instance_desc->GetValue(index),
2073 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2074 details.index());
2075 // Construct a new field descriptors array containing the new descriptor.
2076 Object* descriptors_unchecked;
2077 { MaybeObject* maybe_descriptors_unchecked =
2078 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2079 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2080 return maybe_descriptors_unchecked;
2081 }
2082 }
2083 DescriptorArray* new_descriptors =
2084 DescriptorArray::cast(descriptors_unchecked);
2085 // Create a new map featuring the new field descriptors array.
2086 Object* map_unchecked;
2087 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2088 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2089 return maybe_map_unchecked;
2090 }
2091 }
2092 Map* new_map = Map::cast(map_unchecked);
2093 new_map->set_instance_descriptors(new_descriptors);
2094 function->set_map(new_map);
2095 } else { // Dictionary properties.
2096 // Directly manipulate the property details.
2097 int entry = function->property_dictionary()->FindEntry(name);
2098 ASSERT(entry != StringDictionary::kNotFound);
2099 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2100 PropertyDetails new_details(
2101 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2102 details.type(),
2103 details.index());
2104 function->property_dictionary()->DetailsAtPut(entry, new_details);
2105 }
2106 return function;
2107}
2108
2109
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002110RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002111 NoHandleAllocation ha;
2112 ASSERT(args.length() == 1);
2113
2114 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002115 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002116}
2117
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002118
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002119RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002120 NoHandleAllocation ha;
2121 ASSERT(args.length() == 1);
2122
2123 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002124 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002125}
2126
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002127
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002128RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002129 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002130 ASSERT(args.length() == 2);
2131
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002132 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002133 Handle<Object> code = args.at<Object>(1);
2134
2135 Handle<Context> context(target->context());
2136
2137 if (!code->IsNull()) {
2138 RUNTIME_ASSERT(code->IsJSFunction());
2139 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002140 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002141
2142 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002143 return Failure::Exception();
2144 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002145 // Since we don't store the source for this we should never
2146 // optimize this.
2147 shared->code()->set_optimizable(false);
2148
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002149 // Set the code, scope info, formal parameter count,
2150 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002151 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002152 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002153 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002154 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002155 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002156 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002157 // Set the source code of the target function to undefined.
2158 // SetCode is only used for built-in constructors like String,
2159 // Array, and Object, and some web code
2160 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002161 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002162 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002163 // Clear the optimization hints related to the compiled code as these are no
2164 // longer valid when the code is overwritten.
2165 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002166 context = Handle<Context>(fun->context());
2167
2168 // Make sure we get a fresh copy of the literal vector to avoid
2169 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002170 int number_of_literals = fun->NumberOfLiterals();
2171 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002172 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002173 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002174 // Insert the object, regexp and array functions in the literals
2175 // array prefix. These are the functions that will be used when
2176 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002177 literals->set(JSFunction::kLiteralGlobalContextIndex,
2178 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002179 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002180 // It's okay to skip the write barrier here because the literals
2181 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002182 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002183 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002184 }
2185
2186 target->set_context(*context);
2187 return *target;
2188}
2189
2190
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002191RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002192 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002193 ASSERT(args.length() == 2);
2194 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002195 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002196 RUNTIME_ASSERT(num >= 0);
2197 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002198 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002199}
2200
2201
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002202MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2203 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002204 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002205 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002206 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002207 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002208 }
2209 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002210 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002211}
2212
2213
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002214RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002215 NoHandleAllocation ha;
2216 ASSERT(args.length() == 2);
2217
2218 CONVERT_CHECKED(String, subject, args[0]);
2219 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002220 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002221
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002222 uint32_t i = 0;
2223 if (index->IsSmi()) {
2224 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002225 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002226 i = value;
2227 } else {
2228 ASSERT(index->IsHeapNumber());
2229 double value = HeapNumber::cast(index)->value();
2230 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002231 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002232
2233 // Flatten the string. If someone wants to get a char at an index
2234 // in a cons string, it is likely that more indices will be
2235 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002236 Object* flat;
2237 { MaybeObject* maybe_flat = subject->TryFlatten();
2238 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2239 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002240 subject = String::cast(flat);
2241
2242 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002243 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002244 }
2245
2246 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002247}
2248
2249
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002250RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002251 NoHandleAllocation ha;
2252 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002253 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002254}
2255
lrn@chromium.org25156de2010-04-06 13:10:27 +00002256
2257class FixedArrayBuilder {
2258 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002259 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2260 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002261 length_(0) {
2262 // Require a non-zero initial size. Ensures that doubling the size to
2263 // extend the array will work.
2264 ASSERT(initial_capacity > 0);
2265 }
2266
2267 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2268 : array_(backing_store),
2269 length_(0) {
2270 // Require a non-zero initial size. Ensures that doubling the size to
2271 // extend the array will work.
2272 ASSERT(backing_store->length() > 0);
2273 }
2274
2275 bool HasCapacity(int elements) {
2276 int length = array_->length();
2277 int required_length = length_ + elements;
2278 return (length >= required_length);
2279 }
2280
2281 void EnsureCapacity(int elements) {
2282 int length = array_->length();
2283 int required_length = length_ + elements;
2284 if (length < required_length) {
2285 int new_length = length;
2286 do {
2287 new_length *= 2;
2288 } while (new_length < required_length);
2289 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002290 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002291 array_->CopyTo(0, *extended_array, 0, length_);
2292 array_ = extended_array;
2293 }
2294 }
2295
2296 void Add(Object* value) {
2297 ASSERT(length_ < capacity());
2298 array_->set(length_, value);
2299 length_++;
2300 }
2301
2302 void Add(Smi* value) {
2303 ASSERT(length_ < capacity());
2304 array_->set(length_, value);
2305 length_++;
2306 }
2307
2308 Handle<FixedArray> array() {
2309 return array_;
2310 }
2311
2312 int length() {
2313 return length_;
2314 }
2315
2316 int capacity() {
2317 return array_->length();
2318 }
2319
2320 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002321 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002322 result_array->set_length(Smi::FromInt(length_));
2323 return result_array;
2324 }
2325
2326 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2327 target_array->set_elements(*array_);
2328 target_array->set_length(Smi::FromInt(length_));
2329 return target_array;
2330 }
2331
2332 private:
2333 Handle<FixedArray> array_;
2334 int length_;
2335};
2336
2337
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002338// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002339const int kStringBuilderConcatHelperLengthBits = 11;
2340const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002341
2342template <typename schar>
2343static inline void StringBuilderConcatHelper(String*,
2344 schar*,
2345 FixedArray*,
2346 int);
2347
lrn@chromium.org25156de2010-04-06 13:10:27 +00002348typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2349 StringBuilderSubstringLength;
2350typedef BitField<int,
2351 kStringBuilderConcatHelperLengthBits,
2352 kStringBuilderConcatHelperPositionBits>
2353 StringBuilderSubstringPosition;
2354
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002355
2356class ReplacementStringBuilder {
2357 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002358 ReplacementStringBuilder(Heap* heap,
2359 Handle<String> subject,
2360 int estimated_part_count)
2361 : heap_(heap),
2362 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002363 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002364 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002365 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002366 // Require a non-zero initial size. Ensures that doubling the size to
2367 // extend the array will work.
2368 ASSERT(estimated_part_count > 0);
2369 }
2370
lrn@chromium.org25156de2010-04-06 13:10:27 +00002371 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2372 int from,
2373 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002374 ASSERT(from >= 0);
2375 int length = to - from;
2376 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002377 if (StringBuilderSubstringLength::is_valid(length) &&
2378 StringBuilderSubstringPosition::is_valid(from)) {
2379 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2380 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002381 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002382 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002383 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002384 builder->Add(Smi::FromInt(-length));
2385 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002386 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002387 }
2388
2389
2390 void EnsureCapacity(int elements) {
2391 array_builder_.EnsureCapacity(elements);
2392 }
2393
2394
2395 void AddSubjectSlice(int from, int to) {
2396 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002397 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002398 }
2399
2400
2401 void AddString(Handle<String> string) {
2402 int length = string->length();
2403 ASSERT(length > 0);
2404 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002405 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002406 is_ascii_ = false;
2407 }
2408 IncrementCharacterCount(length);
2409 }
2410
2411
2412 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002413 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002414 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002415 }
2416
2417 Handle<String> joined_string;
2418 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002419 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002420 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002421 char* char_buffer = seq->GetChars();
2422 StringBuilderConcatHelper(*subject_,
2423 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002424 *array_builder_.array(),
2425 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002426 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002427 } else {
2428 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002429 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002430 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002431 uc16* char_buffer = seq->GetChars();
2432 StringBuilderConcatHelper(*subject_,
2433 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002434 *array_builder_.array(),
2435 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002436 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002437 }
2438 return joined_string;
2439 }
2440
2441
2442 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002443 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002444 V8::FatalProcessOutOfMemory("String.replace result too large.");
2445 }
2446 character_count_ += by;
2447 }
2448
lrn@chromium.org25156de2010-04-06 13:10:27 +00002449 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002450 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002451 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002452
lrn@chromium.org25156de2010-04-06 13:10:27 +00002453 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002454 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2455 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002456 }
2457
2458
ager@chromium.org04921a82011-06-27 13:21:41 +00002459 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2460 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002461 }
2462
2463
2464 void AddElement(Object* element) {
2465 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002466 ASSERT(array_builder_.capacity() > array_builder_.length());
2467 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002468 }
2469
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002470 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002471 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002472 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002473 int character_count_;
2474 bool is_ascii_;
2475};
2476
2477
2478class CompiledReplacement {
2479 public:
2480 CompiledReplacement()
2481 : parts_(1), replacement_substrings_(0) {}
2482
2483 void Compile(Handle<String> replacement,
2484 int capture_count,
2485 int subject_length);
2486
2487 void Apply(ReplacementStringBuilder* builder,
2488 int match_from,
2489 int match_to,
2490 Handle<JSArray> last_match_info);
2491
2492 // Number of distinct parts of the replacement pattern.
2493 int parts() {
2494 return parts_.length();
2495 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002496
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002497 private:
2498 enum PartType {
2499 SUBJECT_PREFIX = 1,
2500 SUBJECT_SUFFIX,
2501 SUBJECT_CAPTURE,
2502 REPLACEMENT_SUBSTRING,
2503 REPLACEMENT_STRING,
2504
2505 NUMBER_OF_PART_TYPES
2506 };
2507
2508 struct ReplacementPart {
2509 static inline ReplacementPart SubjectMatch() {
2510 return ReplacementPart(SUBJECT_CAPTURE, 0);
2511 }
2512 static inline ReplacementPart SubjectCapture(int capture_index) {
2513 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2514 }
2515 static inline ReplacementPart SubjectPrefix() {
2516 return ReplacementPart(SUBJECT_PREFIX, 0);
2517 }
2518 static inline ReplacementPart SubjectSuffix(int subject_length) {
2519 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2520 }
2521 static inline ReplacementPart ReplacementString() {
2522 return ReplacementPart(REPLACEMENT_STRING, 0);
2523 }
2524 static inline ReplacementPart ReplacementSubString(int from, int to) {
2525 ASSERT(from >= 0);
2526 ASSERT(to > from);
2527 return ReplacementPart(-from, to);
2528 }
2529
2530 // If tag <= 0 then it is the negation of a start index of a substring of
2531 // the replacement pattern, otherwise it's a value from PartType.
2532 ReplacementPart(int tag, int data)
2533 : tag(tag), data(data) {
2534 // Must be non-positive or a PartType value.
2535 ASSERT(tag < NUMBER_OF_PART_TYPES);
2536 }
2537 // Either a value of PartType or a non-positive number that is
2538 // the negation of an index into the replacement string.
2539 int tag;
2540 // The data value's interpretation depends on the value of tag:
2541 // tag == SUBJECT_PREFIX ||
2542 // tag == SUBJECT_SUFFIX: data is unused.
2543 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2544 // tag == REPLACEMENT_SUBSTRING ||
2545 // tag == REPLACEMENT_STRING: data is index into array of substrings
2546 // of the replacement string.
2547 // tag <= 0: Temporary representation of the substring of the replacement
2548 // string ranging over -tag .. data.
2549 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2550 // substring objects.
2551 int data;
2552 };
2553
2554 template<typename Char>
2555 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2556 Vector<Char> characters,
2557 int capture_count,
2558 int subject_length) {
2559 int length = characters.length();
2560 int last = 0;
2561 for (int i = 0; i < length; i++) {
2562 Char c = characters[i];
2563 if (c == '$') {
2564 int next_index = i + 1;
2565 if (next_index == length) { // No next character!
2566 break;
2567 }
2568 Char c2 = characters[next_index];
2569 switch (c2) {
2570 case '$':
2571 if (i > last) {
2572 // There is a substring before. Include the first "$".
2573 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2574 last = next_index + 1; // Continue after the second "$".
2575 } else {
2576 // Let the next substring start with the second "$".
2577 last = next_index;
2578 }
2579 i = next_index;
2580 break;
2581 case '`':
2582 if (i > last) {
2583 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2584 }
2585 parts->Add(ReplacementPart::SubjectPrefix());
2586 i = next_index;
2587 last = i + 1;
2588 break;
2589 case '\'':
2590 if (i > last) {
2591 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2592 }
2593 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2594 i = next_index;
2595 last = i + 1;
2596 break;
2597 case '&':
2598 if (i > last) {
2599 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2600 }
2601 parts->Add(ReplacementPart::SubjectMatch());
2602 i = next_index;
2603 last = i + 1;
2604 break;
2605 case '0':
2606 case '1':
2607 case '2':
2608 case '3':
2609 case '4':
2610 case '5':
2611 case '6':
2612 case '7':
2613 case '8':
2614 case '9': {
2615 int capture_ref = c2 - '0';
2616 if (capture_ref > capture_count) {
2617 i = next_index;
2618 continue;
2619 }
2620 int second_digit_index = next_index + 1;
2621 if (second_digit_index < length) {
2622 // Peek ahead to see if we have two digits.
2623 Char c3 = characters[second_digit_index];
2624 if ('0' <= c3 && c3 <= '9') { // Double digits.
2625 int double_digit_ref = capture_ref * 10 + c3 - '0';
2626 if (double_digit_ref <= capture_count) {
2627 next_index = second_digit_index;
2628 capture_ref = double_digit_ref;
2629 }
2630 }
2631 }
2632 if (capture_ref > 0) {
2633 if (i > last) {
2634 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2635 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002636 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002637 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2638 last = next_index + 1;
2639 }
2640 i = next_index;
2641 break;
2642 }
2643 default:
2644 i = next_index;
2645 break;
2646 }
2647 }
2648 }
2649 if (length > last) {
2650 if (last == 0) {
2651 parts->Add(ReplacementPart::ReplacementString());
2652 } else {
2653 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2654 }
2655 }
2656 }
2657
2658 ZoneList<ReplacementPart> parts_;
2659 ZoneList<Handle<String> > replacement_substrings_;
2660};
2661
2662
2663void CompiledReplacement::Compile(Handle<String> replacement,
2664 int capture_count,
2665 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002666 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002667 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002668 String::FlatContent content = replacement->GetFlatContent();
2669 ASSERT(content.IsFlat());
2670 if (content.IsAscii()) {
2671 ParseReplacementPattern(&parts_,
2672 content.ToAsciiVector(),
2673 capture_count,
2674 subject_length);
2675 } else {
2676 ASSERT(content.IsTwoByte());
2677 ParseReplacementPattern(&parts_,
2678 content.ToUC16Vector(),
2679 capture_count,
2680 subject_length);
2681 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002682 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002683 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002684 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002685 int substring_index = 0;
2686 for (int i = 0, n = parts_.length(); i < n; i++) {
2687 int tag = parts_[i].tag;
2688 if (tag <= 0) { // A replacement string slice.
2689 int from = -tag;
2690 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002691 replacement_substrings_.Add(
2692 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002693 parts_[i].tag = REPLACEMENT_SUBSTRING;
2694 parts_[i].data = substring_index;
2695 substring_index++;
2696 } else if (tag == REPLACEMENT_STRING) {
2697 replacement_substrings_.Add(replacement);
2698 parts_[i].data = substring_index;
2699 substring_index++;
2700 }
2701 }
2702}
2703
2704
2705void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2706 int match_from,
2707 int match_to,
2708 Handle<JSArray> last_match_info) {
2709 for (int i = 0, n = parts_.length(); i < n; i++) {
2710 ReplacementPart part = parts_[i];
2711 switch (part.tag) {
2712 case SUBJECT_PREFIX:
2713 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2714 break;
2715 case SUBJECT_SUFFIX: {
2716 int subject_length = part.data;
2717 if (match_to < subject_length) {
2718 builder->AddSubjectSlice(match_to, subject_length);
2719 }
2720 break;
2721 }
2722 case SUBJECT_CAPTURE: {
2723 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002724 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002725 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2726 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2727 if (from >= 0 && to > from) {
2728 builder->AddSubjectSlice(from, to);
2729 }
2730 break;
2731 }
2732 case REPLACEMENT_SUBSTRING:
2733 case REPLACEMENT_STRING:
2734 builder->AddString(replacement_substrings_[part.data]);
2735 break;
2736 default:
2737 UNREACHABLE();
2738 }
2739 }
2740}
2741
2742
2743
lrn@chromium.org303ada72010-10-27 09:33:13 +00002744MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002745 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002746 String* subject,
2747 JSRegExp* regexp,
2748 String* replacement,
2749 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002750 ASSERT(subject->IsFlat());
2751 ASSERT(replacement->IsFlat());
2752
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002753 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002754
2755 int length = subject->length();
2756 Handle<String> subject_handle(subject);
2757 Handle<JSRegExp> regexp_handle(regexp);
2758 Handle<String> replacement_handle(replacement);
2759 Handle<JSArray> last_match_info_handle(last_match_info);
2760 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2761 subject_handle,
2762 0,
2763 last_match_info_handle);
2764 if (match.is_null()) {
2765 return Failure::Exception();
2766 }
2767 if (match->IsNull()) {
2768 return *subject_handle;
2769 }
2770
2771 int capture_count = regexp_handle->CaptureCount();
2772
2773 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002774 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002775 CompiledReplacement compiled_replacement;
2776 compiled_replacement.Compile(replacement_handle,
2777 capture_count,
2778 length);
2779
2780 bool is_global = regexp_handle->GetFlags().is_global();
2781
2782 // Guessing the number of parts that the final result string is built
2783 // from. Global regexps can match any number of times, so we guess
2784 // conservatively.
2785 int expected_parts =
2786 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002787 ReplacementStringBuilder builder(isolate->heap(),
2788 subject_handle,
2789 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002790
2791 // Index of end of last match.
2792 int prev = 0;
2793
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002794 // Number of parts added by compiled replacement plus preceeding
2795 // string and possibly suffix after last match. It is possible for
2796 // all components to use two elements when encoded as two smis.
2797 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002798 bool matched = true;
2799 do {
2800 ASSERT(last_match_info_handle->HasFastElements());
2801 // Increase the capacity of the builder before entering local handle-scope,
2802 // so its internal buffer can safely allocate a new handle if it grows.
2803 builder.EnsureCapacity(parts_added_per_loop);
2804
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002805 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002806 int start, end;
2807 {
2808 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002809 FixedArray* match_info_array =
2810 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002811
2812 ASSERT_EQ(capture_count * 2 + 2,
2813 RegExpImpl::GetLastCaptureCount(match_info_array));
2814 start = RegExpImpl::GetCapture(match_info_array, 0);
2815 end = RegExpImpl::GetCapture(match_info_array, 1);
2816 }
2817
2818 if (prev < start) {
2819 builder.AddSubjectSlice(prev, start);
2820 }
2821 compiled_replacement.Apply(&builder,
2822 start,
2823 end,
2824 last_match_info_handle);
2825 prev = end;
2826
2827 // Only continue checking for global regexps.
2828 if (!is_global) break;
2829
2830 // Continue from where the match ended, unless it was an empty match.
2831 int next = end;
2832 if (start == end) {
2833 next = end + 1;
2834 if (next > length) break;
2835 }
2836
2837 match = RegExpImpl::Exec(regexp_handle,
2838 subject_handle,
2839 next,
2840 last_match_info_handle);
2841 if (match.is_null()) {
2842 return Failure::Exception();
2843 }
2844 matched = !match->IsNull();
2845 } while (matched);
2846
2847 if (prev < length) {
2848 builder.AddSubjectSlice(prev, length);
2849 }
2850
2851 return *(builder.ToString());
2852}
2853
2854
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002855template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002856MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002857 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002858 String* subject,
2859 JSRegExp* regexp,
2860 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002861 ASSERT(subject->IsFlat());
2862
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002863 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002864
2865 Handle<String> subject_handle(subject);
2866 Handle<JSRegExp> regexp_handle(regexp);
2867 Handle<JSArray> last_match_info_handle(last_match_info);
2868 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2869 subject_handle,
2870 0,
2871 last_match_info_handle);
2872 if (match.is_null()) return Failure::Exception();
2873 if (match->IsNull()) return *subject_handle;
2874
2875 ASSERT(last_match_info_handle->HasFastElements());
2876
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002877 int start, end;
2878 {
2879 AssertNoAllocation match_info_array_is_not_in_a_handle;
2880 FixedArray* match_info_array =
2881 FixedArray::cast(last_match_info_handle->elements());
2882
2883 start = RegExpImpl::GetCapture(match_info_array, 0);
2884 end = RegExpImpl::GetCapture(match_info_array, 1);
2885 }
2886
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002887 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002888 int new_length = length - (end - start);
2889 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002890 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002891 }
2892 Handle<ResultSeqString> answer;
2893 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002894 answer = Handle<ResultSeqString>::cast(
2895 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002896 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002897 answer = Handle<ResultSeqString>::cast(
2898 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002899 }
2900
2901 // If the regexp isn't global, only match once.
2902 if (!regexp_handle->GetFlags().is_global()) {
2903 if (start > 0) {
2904 String::WriteToFlat(*subject_handle,
2905 answer->GetChars(),
2906 0,
2907 start);
2908 }
2909 if (end < length) {
2910 String::WriteToFlat(*subject_handle,
2911 answer->GetChars() + start,
2912 end,
2913 length);
2914 }
2915 return *answer;
2916 }
2917
2918 int prev = 0; // Index of end of last match.
2919 int next = 0; // Start of next search (prev unless last match was empty).
2920 int position = 0;
2921
2922 do {
2923 if (prev < start) {
2924 // Add substring subject[prev;start] to answer string.
2925 String::WriteToFlat(*subject_handle,
2926 answer->GetChars() + position,
2927 prev,
2928 start);
2929 position += start - prev;
2930 }
2931 prev = end;
2932 next = end;
2933 // Continue from where the match ended, unless it was an empty match.
2934 if (start == end) {
2935 next++;
2936 if (next > length) break;
2937 }
2938 match = RegExpImpl::Exec(regexp_handle,
2939 subject_handle,
2940 next,
2941 last_match_info_handle);
2942 if (match.is_null()) return Failure::Exception();
2943 if (match->IsNull()) break;
2944
2945 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002946 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002947 {
2948 AssertNoAllocation match_info_array_is_not_in_a_handle;
2949 FixedArray* match_info_array =
2950 FixedArray::cast(last_match_info_handle->elements());
2951 start = RegExpImpl::GetCapture(match_info_array, 0);
2952 end = RegExpImpl::GetCapture(match_info_array, 1);
2953 }
2954 } while (true);
2955
2956 if (prev < length) {
2957 // Add substring subject[prev;length] to answer string.
2958 String::WriteToFlat(*subject_handle,
2959 answer->GetChars() + position,
2960 prev,
2961 length);
2962 position += length - prev;
2963 }
2964
2965 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002966 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002967 }
2968
2969 // Shorten string and fill
2970 int string_size = ResultSeqString::SizeFor(position);
2971 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2972 int delta = allocated_string_size - string_size;
2973
2974 answer->set_length(position);
2975 if (delta == 0) return *answer;
2976
2977 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002978 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002979
2980 return *answer;
2981}
2982
2983
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002984RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002985 ASSERT(args.length() == 4);
2986
2987 CONVERT_CHECKED(String, subject, args[0]);
2988 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002989 Object* flat_subject;
2990 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2991 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2992 return maybe_flat_subject;
2993 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002994 }
2995 subject = String::cast(flat_subject);
2996 }
2997
2998 CONVERT_CHECKED(String, replacement, args[2]);
2999 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003000 Object* flat_replacement;
3001 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3002 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3003 return maybe_flat_replacement;
3004 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003005 }
3006 replacement = String::cast(flat_replacement);
3007 }
3008
3009 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3010 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3011
3012 ASSERT(last_match_info->HasFastElements());
3013
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003014 if (replacement->length() == 0) {
3015 if (subject->HasOnlyAsciiChars()) {
3016 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003017 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003018 } else {
3019 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003020 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003021 }
3022 }
3023
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003024 return StringReplaceRegExpWithString(isolate,
3025 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003026 regexp,
3027 replacement,
3028 last_match_info);
3029}
3030
3031
ager@chromium.org7c537e22008-10-16 08:43:32 +00003032// Perform string match of pattern on subject, starting at start index.
3033// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003034// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003035int Runtime::StringMatch(Isolate* isolate,
3036 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003037 Handle<String> pat,
3038 int start_index) {
3039 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003040 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003041
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003042 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003043 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003044
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003045 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003046 if (start_index + pattern_length > subject_length) return -1;
3047
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003048 if (!sub->IsFlat()) FlattenString(sub);
3049 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003050
ager@chromium.org7c537e22008-10-16 08:43:32 +00003051 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003052 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003053 String::FlatContent seq_sub = sub->GetFlatContent();
3054 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003055
ager@chromium.org7c537e22008-10-16 08:43:32 +00003056 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003057 if (seq_pat.IsAscii()) {
3058 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3059 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003060 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003061 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003062 pat_vector,
3063 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003064 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003065 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003066 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003067 pat_vector,
3068 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003069 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003070 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3071 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003072 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003073 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003074 pat_vector,
3075 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003076 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003077 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003078 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003079 pat_vector,
3080 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003081}
3082
3083
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003084RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003085 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003086 ASSERT(args.length() == 3);
3087
ager@chromium.org7c537e22008-10-16 08:43:32 +00003088 CONVERT_ARG_CHECKED(String, sub, 0);
3089 CONVERT_ARG_CHECKED(String, pat, 1);
3090
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003091 Object* index = args[2];
3092 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003093 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003094
ager@chromium.org870a0b62008-11-04 11:43:05 +00003095 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003096 int position =
3097 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003098 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003099}
3100
3101
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003102template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003103static int StringMatchBackwards(Vector<const schar> subject,
3104 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003105 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003106 int pattern_length = pattern.length();
3107 ASSERT(pattern_length >= 1);
3108 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003109
3110 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003111 for (int i = 0; i < pattern_length; i++) {
3112 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003113 if (c > String::kMaxAsciiCharCode) {
3114 return -1;
3115 }
3116 }
3117 }
3118
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003119 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003120 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003121 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003122 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003123 while (j < pattern_length) {
3124 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003125 break;
3126 }
3127 j++;
3128 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003129 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003130 return i;
3131 }
3132 }
3133 return -1;
3134}
3135
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003136RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003137 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003138 ASSERT(args.length() == 3);
3139
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003140 CONVERT_ARG_CHECKED(String, sub, 0);
3141 CONVERT_ARG_CHECKED(String, pat, 1);
3142
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003143 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003144 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003145 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003146
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003147 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003148 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003149
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003150 if (start_index + pat_length > sub_length) {
3151 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003152 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003153
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003154 if (pat_length == 0) {
3155 return Smi::FromInt(start_index);
3156 }
3157
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003158 if (!sub->IsFlat()) FlattenString(sub);
3159 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003160
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003161 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003162 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3163
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003164 String::FlatContent sub_content = sub->GetFlatContent();
3165 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003166
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003167 if (pat_content.IsAscii()) {
3168 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3169 if (sub_content.IsAscii()) {
3170 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003171 pat_vector,
3172 start_index);
3173 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003174 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003175 pat_vector,
3176 start_index);
3177 }
3178 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003179 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3180 if (sub_content.IsAscii()) {
3181 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003182 pat_vector,
3183 start_index);
3184 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003185 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003186 pat_vector,
3187 start_index);
3188 }
3189 }
3190
3191 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003192}
3193
3194
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003195RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003196 NoHandleAllocation ha;
3197 ASSERT(args.length() == 2);
3198
3199 CONVERT_CHECKED(String, str1, args[0]);
3200 CONVERT_CHECKED(String, str2, args[1]);
3201
3202 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003203 int str1_length = str1->length();
3204 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003205
3206 // Decide trivial cases without flattening.
3207 if (str1_length == 0) {
3208 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3209 return Smi::FromInt(-str2_length);
3210 } else {
3211 if (str2_length == 0) return Smi::FromInt(str1_length);
3212 }
3213
3214 int end = str1_length < str2_length ? str1_length : str2_length;
3215
3216 // No need to flatten if we are going to find the answer on the first
3217 // character. At this point we know there is at least one character
3218 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003219 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003220 if (d != 0) return Smi::FromInt(d);
3221
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003222 str1->TryFlatten();
3223 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003224
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003225 StringInputBuffer& buf1 =
3226 *isolate->runtime_state()->string_locale_compare_buf1();
3227 StringInputBuffer& buf2 =
3228 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003229
3230 buf1.Reset(str1);
3231 buf2.Reset(str2);
3232
3233 for (int i = 0; i < end; i++) {
3234 uint16_t char1 = buf1.GetNext();
3235 uint16_t char2 = buf2.GetNext();
3236 if (char1 != char2) return Smi::FromInt(char1 - char2);
3237 }
3238
3239 return Smi::FromInt(str1_length - str2_length);
3240}
3241
3242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003243RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003244 NoHandleAllocation ha;
3245 ASSERT(args.length() == 3);
3246
3247 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003248 int start, end;
3249 // We have a fast integer-only case here to avoid a conversion to double in
3250 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003251 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3252 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3253 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3254 start = from_number;
3255 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003256 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003257 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3258 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003259 start = FastD2I(from_number);
3260 end = FastD2I(to_number);
3261 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003262 RUNTIME_ASSERT(end >= start);
3263 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003264 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003265 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003266 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003267}
3268
3269
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003270RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003271 ASSERT_EQ(3, args.length());
3272
3273 CONVERT_ARG_CHECKED(String, subject, 0);
3274 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3275 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3276 HandleScope handles;
3277
3278 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3279
3280 if (match.is_null()) {
3281 return Failure::Exception();
3282 }
3283 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003284 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003285 }
3286 int length = subject->length();
3287
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003288 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003289 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003290 int start;
3291 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003292 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003293 {
3294 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003295 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003296 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3297 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3298 }
3299 offsets.Add(start);
3300 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003301 if (start == end) if (++end > length) break;
3302 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003303 if (match.is_null()) {
3304 return Failure::Exception();
3305 }
3306 } while (!match->IsNull());
3307 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003308 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003309 Handle<String> substring = isolate->factory()->
3310 NewSubString(subject, offsets.at(0), offsets.at(1));
3311 elements->set(0, *substring);
3312 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003313 int from = offsets.at(i * 2);
3314 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003315 Handle<String> substring = isolate->factory()->
3316 NewProperSubString(subject, from, to);
3317 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003318 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003319 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003320 result->set_length(Smi::FromInt(matches));
3321 return *result;
3322}
3323
3324
lrn@chromium.org25156de2010-04-06 13:10:27 +00003325// Two smis before and after the match, for very long strings.
3326const int kMaxBuilderEntriesPerRegExpMatch = 5;
3327
3328
3329static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3330 Handle<JSArray> last_match_info,
3331 int match_start,
3332 int match_end) {
3333 // Fill last_match_info with a single capture.
3334 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3335 AssertNoAllocation no_gc;
3336 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3337 RegExpImpl::SetLastCaptureCount(elements, 2);
3338 RegExpImpl::SetLastInput(elements, *subject);
3339 RegExpImpl::SetLastSubject(elements, *subject);
3340 RegExpImpl::SetCapture(elements, 0, match_start);
3341 RegExpImpl::SetCapture(elements, 1, match_end);
3342}
3343
3344
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003345template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003346static bool SearchStringMultiple(Isolate* isolate,
3347 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003348 Vector<const PatternChar> pattern,
3349 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003350 FixedArrayBuilder* builder,
3351 int* match_pos) {
3352 int pos = *match_pos;
3353 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003354 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003355 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003356 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003357 while (pos <= max_search_start) {
3358 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3359 *match_pos = pos;
3360 return false;
3361 }
3362 // Position of end of previous match.
3363 int match_end = pos + pattern_length;
3364 int new_pos = search.Search(subject, match_end);
3365 if (new_pos >= 0) {
3366 // A match.
3367 if (new_pos > match_end) {
3368 ReplacementStringBuilder::AddSubjectSlice(builder,
3369 match_end,
3370 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003371 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003372 pos = new_pos;
3373 builder->Add(pattern_string);
3374 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003375 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003376 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003377 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003378
lrn@chromium.org25156de2010-04-06 13:10:27 +00003379 if (pos < max_search_start) {
3380 ReplacementStringBuilder::AddSubjectSlice(builder,
3381 pos + pattern_length,
3382 subject_length);
3383 }
3384 *match_pos = pos;
3385 return true;
3386}
3387
3388
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003389static bool SearchStringMultiple(Isolate* isolate,
3390 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003391 Handle<String> pattern,
3392 Handle<JSArray> last_match_info,
3393 FixedArrayBuilder* builder) {
3394 ASSERT(subject->IsFlat());
3395 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003396
3397 // Treating as if a previous match was before first character.
3398 int match_pos = -pattern->length();
3399
3400 for (;;) { // Break when search complete.
3401 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3402 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003403 String::FlatContent subject_content = subject->GetFlatContent();
3404 String::FlatContent pattern_content = pattern->GetFlatContent();
3405 if (subject_content.IsAscii()) {
3406 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3407 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003408 if (SearchStringMultiple(isolate,
3409 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003410 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003411 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003412 builder,
3413 &match_pos)) break;
3414 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003415 if (SearchStringMultiple(isolate,
3416 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003417 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003418 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003419 builder,
3420 &match_pos)) break;
3421 }
3422 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003423 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3424 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003425 if (SearchStringMultiple(isolate,
3426 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003427 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003428 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003429 builder,
3430 &match_pos)) break;
3431 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003432 if (SearchStringMultiple(isolate,
3433 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003434 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003435 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003436 builder,
3437 &match_pos)) break;
3438 }
3439 }
3440 }
3441
3442 if (match_pos >= 0) {
3443 SetLastMatchInfoNoCaptures(subject,
3444 last_match_info,
3445 match_pos,
3446 match_pos + pattern->length());
3447 return true;
3448 }
3449 return false; // No matches at all.
3450}
3451
3452
3453static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003454 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003455 Handle<String> subject,
3456 Handle<JSRegExp> regexp,
3457 Handle<JSArray> last_match_array,
3458 FixedArrayBuilder* builder) {
3459 ASSERT(subject->IsFlat());
3460 int match_start = -1;
3461 int match_end = 0;
3462 int pos = 0;
3463 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3464 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3465
3466 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003467 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003468 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003469 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003470
3471 for (;;) { // Break on failure, return on exception.
3472 RegExpImpl::IrregexpResult result =
3473 RegExpImpl::IrregexpExecOnce(regexp,
3474 subject,
3475 pos,
3476 register_vector);
3477 if (result == RegExpImpl::RE_SUCCESS) {
3478 match_start = register_vector[0];
3479 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3480 if (match_end < match_start) {
3481 ReplacementStringBuilder::AddSubjectSlice(builder,
3482 match_end,
3483 match_start);
3484 }
3485 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003486 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003487 if (!first) {
3488 builder->Add(*isolate->factory()->NewProperSubString(subject,
3489 match_start,
3490 match_end));
3491 } else {
3492 builder->Add(*isolate->factory()->NewSubString(subject,
3493 match_start,
3494 match_end));
3495 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003496 if (match_start != match_end) {
3497 pos = match_end;
3498 } else {
3499 pos = match_end + 1;
3500 if (pos > subject_length) break;
3501 }
3502 } else if (result == RegExpImpl::RE_FAILURE) {
3503 break;
3504 } else {
3505 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3506 return result;
3507 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003508 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003509 }
3510
3511 if (match_start >= 0) {
3512 if (match_end < subject_length) {
3513 ReplacementStringBuilder::AddSubjectSlice(builder,
3514 match_end,
3515 subject_length);
3516 }
3517 SetLastMatchInfoNoCaptures(subject,
3518 last_match_array,
3519 match_start,
3520 match_end);
3521 return RegExpImpl::RE_SUCCESS;
3522 } else {
3523 return RegExpImpl::RE_FAILURE; // No matches at all.
3524 }
3525}
3526
3527
3528static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003529 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003530 Handle<String> subject,
3531 Handle<JSRegExp> regexp,
3532 Handle<JSArray> last_match_array,
3533 FixedArrayBuilder* builder) {
3534
3535 ASSERT(subject->IsFlat());
3536 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3537 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3538
3539 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003540 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003541
3542 RegExpImpl::IrregexpResult result =
3543 RegExpImpl::IrregexpExecOnce(regexp,
3544 subject,
3545 0,
3546 register_vector);
3547
3548 int capture_count = regexp->CaptureCount();
3549 int subject_length = subject->length();
3550
3551 // Position to search from.
3552 int pos = 0;
3553 // End of previous match. Differs from pos if match was empty.
3554 int match_end = 0;
3555 if (result == RegExpImpl::RE_SUCCESS) {
3556 // Need to keep a copy of the previous match for creating last_match_info
3557 // at the end, so we have two vectors that we swap between.
3558 OffsetsVector registers2(required_registers);
3559 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003560 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003561 do {
3562 int match_start = register_vector[0];
3563 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3564 if (match_end < match_start) {
3565 ReplacementStringBuilder::AddSubjectSlice(builder,
3566 match_end,
3567 match_start);
3568 }
3569 match_end = register_vector[1];
3570
3571 {
3572 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003573 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003574 // Arguments array to replace function is match, captures, index and
3575 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003576 Handle<FixedArray> elements =
3577 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003578 Handle<String> match;
3579 if (!first) {
3580 match = isolate->factory()->NewProperSubString(subject,
3581 match_start,
3582 match_end);
3583 } else {
3584 match = isolate->factory()->NewSubString(subject,
3585 match_start,
3586 match_end);
3587 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003588 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003589 for (int i = 1; i <= capture_count; i++) {
3590 int start = register_vector[i * 2];
3591 if (start >= 0) {
3592 int end = register_vector[i * 2 + 1];
3593 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003594 Handle<String> substring;
3595 if (!first) {
3596 substring = isolate->factory()->NewProperSubString(subject,
3597 start,
3598 end);
3599 } else {
3600 substring = isolate->factory()->NewSubString(subject, start, end);
3601 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003602 elements->set(i, *substring);
3603 } else {
3604 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003605 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003606 }
3607 }
3608 elements->set(capture_count + 1, Smi::FromInt(match_start));
3609 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003610 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003611 }
3612 // Swap register vectors, so the last successful match is in
3613 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003614 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003615 prev_register_vector = register_vector;
3616 register_vector = tmp;
3617
3618 if (match_end > match_start) {
3619 pos = match_end;
3620 } else {
3621 pos = match_end + 1;
3622 if (pos > subject_length) {
3623 break;
3624 }
3625 }
3626
3627 result = RegExpImpl::IrregexpExecOnce(regexp,
3628 subject,
3629 pos,
3630 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003631 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003632 } while (result == RegExpImpl::RE_SUCCESS);
3633
3634 if (result != RegExpImpl::RE_EXCEPTION) {
3635 // Finished matching, with at least one match.
3636 if (match_end < subject_length) {
3637 ReplacementStringBuilder::AddSubjectSlice(builder,
3638 match_end,
3639 subject_length);
3640 }
3641
3642 int last_match_capture_count = (capture_count + 1) * 2;
3643 int last_match_array_size =
3644 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3645 last_match_array->EnsureSize(last_match_array_size);
3646 AssertNoAllocation no_gc;
3647 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3648 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3649 RegExpImpl::SetLastSubject(elements, *subject);
3650 RegExpImpl::SetLastInput(elements, *subject);
3651 for (int i = 0; i < last_match_capture_count; i++) {
3652 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3653 }
3654 return RegExpImpl::RE_SUCCESS;
3655 }
3656 }
3657 // No matches at all, return failure or exception result directly.
3658 return result;
3659}
3660
3661
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003662RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003663 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003664 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003665
3666 CONVERT_ARG_CHECKED(String, subject, 1);
3667 if (!subject->IsFlat()) { FlattenString(subject); }
3668 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3669 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3670 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3671
3672 ASSERT(last_match_info->HasFastElements());
3673 ASSERT(regexp->GetFlags().is_global());
3674 Handle<FixedArray> result_elements;
3675 if (result_array->HasFastElements()) {
3676 result_elements =
3677 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003678 }
3679 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003680 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003681 }
3682 FixedArrayBuilder builder(result_elements);
3683
3684 if (regexp->TypeTag() == JSRegExp::ATOM) {
3685 Handle<String> pattern(
3686 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003687 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003688 if (SearchStringMultiple(isolate, subject, pattern,
3689 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003690 return *builder.ToJSArray(result_array);
3691 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003692 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003693 }
3694
3695 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3696
3697 RegExpImpl::IrregexpResult result;
3698 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003699 result = SearchRegExpNoCaptureMultiple(isolate,
3700 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003701 regexp,
3702 last_match_info,
3703 &builder);
3704 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003705 result = SearchRegExpMultiple(isolate,
3706 subject,
3707 regexp,
3708 last_match_info,
3709 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003710 }
3711 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003712 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003713 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3714 return Failure::Exception();
3715}
3716
3717
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003718RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003719 NoHandleAllocation ha;
3720 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003721 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003722 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003723
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003724 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003725 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003726 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003727 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003728 // Character array used for conversion.
3729 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003730 return isolate->heap()->
3731 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003732 }
3733 }
3734
3735 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003736 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003737 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003738 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003739 }
3740 if (isinf(value)) {
3741 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003742 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003743 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003744 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003745 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003746 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003747 MaybeObject* result =
3748 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003749 DeleteArray(str);
3750 return result;
3751}
3752
3753
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003754RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003755 NoHandleAllocation ha;
3756 ASSERT(args.length() == 2);
3757
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003758 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003759 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003760 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003761 }
3762 if (isinf(value)) {
3763 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003764 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003765 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003766 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003767 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003768 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003769 int f = FastD2I(f_number);
3770 RUNTIME_ASSERT(f >= 0);
3771 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003772 MaybeObject* res =
3773 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003774 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003775 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003776}
3777
3778
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003779RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003780 NoHandleAllocation ha;
3781 ASSERT(args.length() == 2);
3782
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003783 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003784 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003785 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003786 }
3787 if (isinf(value)) {
3788 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003789 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003790 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003791 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003792 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003793 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003794 int f = FastD2I(f_number);
3795 RUNTIME_ASSERT(f >= -1 && f <= 20);
3796 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003797 MaybeObject* res =
3798 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003799 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003800 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003801}
3802
3803
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003804RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003805 NoHandleAllocation ha;
3806 ASSERT(args.length() == 2);
3807
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003808 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003809 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003810 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003811 }
3812 if (isinf(value)) {
3813 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003814 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003815 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003816 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003817 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003818 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003819 int f = FastD2I(f_number);
3820 RUNTIME_ASSERT(f >= 1 && f <= 21);
3821 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003822 MaybeObject* res =
3823 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003824 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003825 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003826}
3827
3828
3829// Returns a single character string where first character equals
3830// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003831static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003832 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003833 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003834 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003835 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003836 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003837 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003838}
3839
3840
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003841MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3842 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003843 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003844 // Handle [] indexing on Strings
3845 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003846 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3847 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003848 }
3849
3850 // Handle [] indexing on String objects
3851 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003852 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3853 Handle<Object> result =
3854 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3855 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003856 }
3857
3858 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003859 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003860 return prototype->GetElement(index);
3861 }
3862
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003863 return GetElement(object, index);
3864}
3865
3866
lrn@chromium.org303ada72010-10-27 09:33:13 +00003867MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003868 return object->GetElement(index);
3869}
3870
3871
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003872MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3873 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003874 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003875 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003876
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003877 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003878 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003879 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003880 isolate->factory()->NewTypeError("non_object_property_load",
3881 HandleVector(args, 2));
3882 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003883 }
3884
3885 // Check if the given key is an array index.
3886 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003887 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003888 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003889 }
3890
3891 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003892 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003893 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003894 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003895 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003896 bool has_pending_exception = false;
3897 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003898 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003899 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003900 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003901 }
3902
ager@chromium.org32912102009-01-16 10:38:43 +00003903 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003904 // the element if so.
3905 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003906 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003907 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003908 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003909 }
3910}
3911
3912
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003913RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003914 NoHandleAllocation ha;
3915 ASSERT(args.length() == 2);
3916
3917 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003918 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003919
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003920 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003921}
3922
3923
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003924// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003925RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003926 NoHandleAllocation ha;
3927 ASSERT(args.length() == 2);
3928
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003929 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003930 // itself.
3931 //
3932 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003933 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003934 // global proxy object never has properties. This is the case
3935 // because the global proxy object forwards everything to its hidden
3936 // prototype including local lookups.
3937 //
3938 // Additionally, we need to make sure that we do not cache results
3939 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003940 if (args[0]->IsJSObject() &&
3941 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003942 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003943 args[1]->IsString()) {
3944 JSObject* receiver = JSObject::cast(args[0]);
3945 String* key = String::cast(args[1]);
3946 if (receiver->HasFastProperties()) {
3947 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003948 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003949 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3950 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003951 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003952 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003953 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003954 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003955 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003956 LookupResult result;
3957 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003958 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003959 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003960 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003961 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003962 }
3963 } else {
3964 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003965 StringDictionary* dictionary = receiver->property_dictionary();
3966 int entry = dictionary->FindEntry(key);
3967 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003968 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003969 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003970 if (!receiver->IsGlobalObject()) return value;
3971 value = JSGlobalPropertyCell::cast(value)->value();
3972 if (!value->IsTheHole()) return value;
3973 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003974 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003975 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003976 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3977 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003978 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003979 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003980 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003981 if (index >= 0 && index < str->length()) {
3982 Handle<Object> result = GetCharAt(str, index);
3983 return *result;
3984 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003985 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003986
3987 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003988 return Runtime::GetObjectProperty(isolate,
3989 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003990 args.at<Object>(1));
3991}
3992
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003993// Implements part of 8.12.9 DefineOwnProperty.
3994// There are 3 cases that lead here:
3995// Step 4b - define a new accessor property.
3996// Steps 9c & 12 - replace an existing data property with an accessor property.
3997// Step 12 - update an existing accessor property with an accessor or generic
3998// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003999RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004000 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004001 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004002 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4003 CONVERT_CHECKED(String, name, args[1]);
4004 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004005 Object* fun = args[3];
4006 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004007 CONVERT_CHECKED(Smi, flag_attr, args[4]);
4008 int unchecked = flag_attr->value();
4009 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4010 RUNTIME_ASSERT(!obj->IsNull());
4011 LookupResult result;
4012 obj->LocalLookupRealNamedProperty(name, &result);
4013
4014 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4015 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
4016 // delete it to avoid running into trouble in DefineAccessor, which
4017 // handles this incorrectly if the property is readonly (does nothing)
4018 if (result.IsProperty() &&
4019 (result.type() == FIELD || result.type() == NORMAL
4020 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004021 Object* ok;
4022 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004023 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004024 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4025 }
ager@chromium.org5c838252010-02-19 08:53:10 +00004026 }
4027 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4028}
4029
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004030// Implements part of 8.12.9 DefineOwnProperty.
4031// There are 3 cases that lead here:
4032// Step 4a - define a new data property.
4033// Steps 9b & 12 - replace an existing accessor property with a data property.
4034// Step 12 - update an existing data property with a data or generic
4035// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004036RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004037 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004038 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004039 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4040 CONVERT_ARG_CHECKED(String, name, 1);
4041 Handle<Object> obj_value = args.at<Object>(2);
4042
4043 CONVERT_CHECKED(Smi, flag, args[3]);
4044 int unchecked = flag->value();
4045 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4046
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004047 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4048
4049 // Check if this is an element.
4050 uint32_t index;
4051 bool is_element = name->AsArrayIndex(&index);
4052
4053 // Special case for elements if any of the flags are true.
4054 // If elements are in fast case we always implicitly assume that:
4055 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4056 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
4057 is_element) {
4058 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004059 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004060 // We do not need to do access checks here since these has already
4061 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004062 Handle<Object> proto(js_object->GetPrototype());
4063 // If proxy is detached, ignore the assignment. Alternatively,
4064 // we could throw an exception.
4065 if (proto->IsNull()) return *obj_value;
4066 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004067 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004068 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004069 // Make sure that we never go back to fast case.
4070 dictionary->set_requires_slow_elements();
4071 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004072 Handle<NumberDictionary> extended_dictionary =
4073 NumberDictionarySet(dictionary, index, obj_value, details);
4074 if (*extended_dictionary != *dictionary) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004075 if (js_object->GetElementsKind() ==
4076 JSObject::NON_STRICT_ARGUMENTS_ELEMENTS) {
4077 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4078 } else {
4079 js_object->set_elements(*extended_dictionary);
4080 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004081 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004082 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004083 }
4084
ager@chromium.org5c838252010-02-19 08:53:10 +00004085 LookupResult result;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004086 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004087
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004088 // To be compatible with safari we do not change the value on API objects
4089 // in defineProperty. Firefox disagrees here, and actually changes the value.
4090 if (result.IsProperty() &&
4091 (result.type() == CALLBACKS) &&
4092 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004093 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004094 }
4095
ager@chromium.org5c838252010-02-19 08:53:10 +00004096 // Take special care when attributes are different and there is already
4097 // a property. For simplicity we normalize the property which enables us
4098 // to not worry about changing the instance_descriptor and creating a new
4099 // map. The current version of SetObjectProperty does not handle attributes
4100 // correctly in the case where a property is a field and is reset with
4101 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004102 if (result.IsProperty() &&
4103 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004104 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004105 if (js_object->IsJSGlobalProxy()) {
4106 // Since the result is a property, the prototype will exist so
4107 // we don't have to check for null.
4108 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004109 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004110 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004111 // Use IgnoreAttributes version since a readonly property may be
4112 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004113 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4114 *obj_value,
4115 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004116 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004117
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004118 return Runtime::ForceSetObjectProperty(isolate,
4119 js_object,
4120 name,
4121 obj_value,
4122 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004123}
4124
4125
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004126// Special case for elements if any of the flags are true.
4127// If elements are in fast case we always implicitly assume that:
4128// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4129static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4130 Handle<JSObject> js_object,
4131 uint32_t index,
4132 Handle<Object> value,
4133 PropertyAttributes attr) {
4134 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004135 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004136 // Make sure that we never go back to fast case.
4137 dictionary->set_requires_slow_elements();
4138 PropertyDetails details = PropertyDetails(attr, NORMAL);
4139 Handle<NumberDictionary> extended_dictionary =
4140 NumberDictionarySet(dictionary, index, value, details);
4141 if (*extended_dictionary != *dictionary) {
4142 js_object->set_elements(*extended_dictionary);
4143 }
4144 return *value;
4145}
4146
4147
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004148MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4149 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004150 Handle<Object> key,
4151 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004152 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004153 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004154 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004155
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004156 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004157 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004158 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004159 isolate->factory()->NewTypeError("non_object_property_store",
4160 HandleVector(args, 2));
4161 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004162 }
4163
4164 // If the object isn't a JavaScript object, we ignore the store.
4165 if (!object->IsJSObject()) return *value;
4166
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004167 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4168
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004169 // Check if the given key is an array index.
4170 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004171 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004172 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4173 // of a string using [] notation. We need to support this too in
4174 // JavaScript.
4175 // In the case of a String object we just need to redirect the assignment to
4176 // the underlying string if the index is in range. Since the underlying
4177 // string does nothing with the assignment then we can ignore such
4178 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004179 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004180 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004181 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004182
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004183 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4184 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4185 }
4186
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004187 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004188 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004189 return *value;
4190 }
4191
4192 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004193 Handle<Object> result;
4194 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004195 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4196 return NormalizeObjectSetElement(isolate,
4197 js_object,
4198 index,
4199 value,
4200 attr);
4201 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004202 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004203 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004204 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004205 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004206 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004207 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004208 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004209 return *value;
4210 }
4211
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004212 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004213 bool has_pending_exception = false;
4214 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4215 if (has_pending_exception) return Failure::Exception();
4216 Handle<String> name = Handle<String>::cast(converted);
4217
4218 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004219 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004220 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004221 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004222 }
4223}
4224
4225
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004226MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4227 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004228 Handle<Object> key,
4229 Handle<Object> value,
4230 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004231 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004232
4233 // Check if the given key is an array index.
4234 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004235 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004236 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4237 // of a string using [] notation. We need to support this too in
4238 // JavaScript.
4239 // In the case of a String object we just need to redirect the assignment to
4240 // the underlying string if the index is in range. Since the underlying
4241 // string does nothing with the assignment then we can ignore such
4242 // assignments.
4243 if (js_object->IsStringObjectWithCharacterAt(index)) {
4244 return *value;
4245 }
4246
whesse@chromium.org7b260152011-06-20 15:33:18 +00004247 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004248 }
4249
4250 if (key->IsString()) {
4251 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004252 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004253 } else {
4254 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004255 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004256 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4257 *value,
4258 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004259 }
4260 }
4261
4262 // Call-back into JavaScript to convert the key to a string.
4263 bool has_pending_exception = false;
4264 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4265 if (has_pending_exception) return Failure::Exception();
4266 Handle<String> name = Handle<String>::cast(converted);
4267
4268 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004269 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004270 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004271 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004272 }
4273}
4274
4275
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004276MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004277 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004278 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004279 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004280
4281 // Check if the given key is an array index.
4282 uint32_t index;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004283 if (receiver->IsJSObject() && key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004284 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4285 // characters of a string using [] notation. In the case of a
4286 // String object we just need to redirect the deletion to the
4287 // underlying string if the index is in range. Since the
4288 // underlying string does nothing with the deletion, we can ignore
4289 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004290 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004291 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004292 }
4293
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004294 return JSObject::cast(*receiver)->DeleteElement(
4295 index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004296 }
4297
4298 Handle<String> key_string;
4299 if (key->IsString()) {
4300 key_string = Handle<String>::cast(key);
4301 } else {
4302 // Call-back into JavaScript to convert the key to a string.
4303 bool has_pending_exception = false;
4304 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4305 if (has_pending_exception) return Failure::Exception();
4306 key_string = Handle<String>::cast(converted);
4307 }
4308
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004309 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004310 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004311}
4312
4313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004314RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004315 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004316 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004317
4318 Handle<Object> object = args.at<Object>(0);
4319 Handle<Object> key = args.at<Object>(1);
4320 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004321 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004322 RUNTIME_ASSERT(
4323 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004324 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004325 PropertyAttributes attributes =
4326 static_cast<PropertyAttributes>(unchecked_attributes);
4327
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004328 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004329 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004330 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004331 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4332 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004333 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004334 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004335
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004336 return Runtime::SetObjectProperty(isolate,
4337 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004338 key,
4339 value,
4340 attributes,
4341 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004342}
4343
4344
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004345// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004346// This is used to decide if we should transform null and undefined
4347// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004348RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004349 NoHandleAllocation ha;
4350 RUNTIME_ASSERT(args.length() == 1);
4351
4352 Handle<Object> object = args.at<Object>(0);
4353
4354 if (object->IsJSFunction()) {
4355 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004356 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004357 }
4358 return isolate->heap()->undefined_value();
4359}
4360
4361
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004362// Set a local property, even if it is READ_ONLY. If the property does not
4363// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004364RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004365 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004366 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004367 CONVERT_CHECKED(JSObject, object, args[0]);
4368 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004369 // Compute attributes.
4370 PropertyAttributes attributes = NONE;
4371 if (args.length() == 4) {
4372 CONVERT_CHECKED(Smi, value_obj, args[3]);
4373 int unchecked_value = value_obj->value();
4374 // Only attribute bits should be set.
4375 RUNTIME_ASSERT(
4376 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4377 attributes = static_cast<PropertyAttributes>(unchecked_value);
4378 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004379
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004380 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004381 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004382}
4383
4384
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004385RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004386 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004387 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004388
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004389 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004390 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004391 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004392 return object->DeleteProperty(key, (strict == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004393 ? JSReceiver::STRICT_DELETION
4394 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004395}
4396
4397
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004398static Object* HasLocalPropertyImplementation(Isolate* isolate,
4399 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004400 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004401 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004402 // Handle hidden prototypes. If there's a hidden prototype above this thing
4403 // then we have to check it for properties, because they are supposed to
4404 // look like they are on this object.
4405 Handle<Object> proto(object->GetPrototype());
4406 if (proto->IsJSObject() &&
4407 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004408 return HasLocalPropertyImplementation(isolate,
4409 Handle<JSObject>::cast(proto),
4410 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004411 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004412 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004413}
4414
4415
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004416RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004417 NoHandleAllocation ha;
4418 ASSERT(args.length() == 2);
4419 CONVERT_CHECKED(String, key, args[1]);
4420
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004421 uint32_t index;
4422 const bool key_is_array_index = key->AsArrayIndex(&index);
4423
ager@chromium.org9085a012009-05-11 19:22:57 +00004424 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004425 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004426 if (obj->IsJSObject()) {
4427 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004428 // Fast case: either the key is a real named property or it is not
4429 // an array index and there are no interceptors or hidden
4430 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004431 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004432 Map* map = object->map();
4433 if (!key_is_array_index &&
4434 !map->has_named_interceptor() &&
4435 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4436 return isolate->heap()->false_value();
4437 }
4438 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004439 HandleScope scope(isolate);
4440 return HasLocalPropertyImplementation(isolate,
4441 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004442 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004443 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004444 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004445 String* string = String::cast(obj);
4446 if (index < static_cast<uint32_t>(string->length())) {
4447 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004448 }
4449 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004450 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004451}
4452
4453
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004454RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004455 NoHandleAllocation na;
4456 ASSERT(args.length() == 2);
4457
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004458 // Only JS receivers can have properties.
4459 if (args[0]->IsJSReceiver()) {
4460 JSReceiver* receiver = JSReceiver::cast(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004461 CONVERT_CHECKED(String, key, args[1]);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004462 if (receiver->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004463 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004464 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004465}
4466
4467
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004468RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004469 NoHandleAllocation na;
4470 ASSERT(args.length() == 2);
4471
4472 // Only JS objects can have elements.
4473 if (args[0]->IsJSObject()) {
4474 JSObject* object = JSObject::cast(args[0]);
4475 CONVERT_CHECKED(Smi, index_obj, args[1]);
4476 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004477 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004478 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004479 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004480}
4481
4482
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004483RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004484 NoHandleAllocation ha;
4485 ASSERT(args.length() == 2);
4486
4487 CONVERT_CHECKED(JSObject, object, args[0]);
4488 CONVERT_CHECKED(String, key, args[1]);
4489
4490 uint32_t index;
4491 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004492 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004493 }
4494
ager@chromium.org870a0b62008-11-04 11:43:05 +00004495 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004496 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004497}
4498
4499
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004500RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004501 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004502 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004503 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004504 return *GetKeysFor(object);
4505}
4506
4507
4508// Returns either a FixedArray as Runtime_GetPropertyNames,
4509// or, if the given object has an enum cache that contains
4510// all enumerable properties of the object and its prototypes
4511// have none, the map of the object. This is used to speed up
4512// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004513RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004514 ASSERT(args.length() == 1);
4515
4516 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4517
4518 if (raw_object->IsSimpleEnum()) return raw_object->map();
4519
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004520 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004521 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004522 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4523 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004524
4525 // Test again, since cache may have been built by preceding call.
4526 if (object->IsSimpleEnum()) return object->map();
4527
4528 return *content;
4529}
4530
4531
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004532// Find the length of the prototype chain that is to to handled as one. If a
4533// prototype object is hidden it is to be viewed as part of the the object it
4534// is prototype for.
4535static int LocalPrototypeChainLength(JSObject* obj) {
4536 int count = 1;
4537 Object* proto = obj->GetPrototype();
4538 while (proto->IsJSObject() &&
4539 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4540 count++;
4541 proto = JSObject::cast(proto)->GetPrototype();
4542 }
4543 return count;
4544}
4545
4546
4547// Return the names of the local named properties.
4548// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004549RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004550 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004551 ASSERT(args.length() == 1);
4552 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004553 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004554 }
4555 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4556
4557 // Skip the global proxy as it has no properties and always delegates to the
4558 // real global object.
4559 if (obj->IsJSGlobalProxy()) {
4560 // Only collect names if access is permitted.
4561 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004562 !isolate->MayNamedAccess(*obj,
4563 isolate->heap()->undefined_value(),
4564 v8::ACCESS_KEYS)) {
4565 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4566 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004567 }
4568 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4569 }
4570
4571 // Find the number of objects making up this.
4572 int length = LocalPrototypeChainLength(*obj);
4573
4574 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004575 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004576 int total_property_count = 0;
4577 Handle<JSObject> jsproto = obj;
4578 for (int i = 0; i < length; i++) {
4579 // Only collect names if access is permitted.
4580 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004581 !isolate->MayNamedAccess(*jsproto,
4582 isolate->heap()->undefined_value(),
4583 v8::ACCESS_KEYS)) {
4584 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4585 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004586 }
4587 int n;
4588 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4589 local_property_count[i] = n;
4590 total_property_count += n;
4591 if (i < length - 1) {
4592 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4593 }
4594 }
4595
4596 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004597 Handle<FixedArray> names =
4598 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004599
4600 // Get the property names.
4601 jsproto = obj;
4602 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004603 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004604 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004605 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4606 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004607 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004608 proto_with_hidden_properties++;
4609 }
4610 if (i < length - 1) {
4611 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4612 }
4613 }
4614
4615 // Filter out name of hidden propeties object.
4616 if (proto_with_hidden_properties > 0) {
4617 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004618 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004619 names->length() - proto_with_hidden_properties);
4620 int dest_pos = 0;
4621 for (int i = 0; i < total_property_count; i++) {
4622 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004623 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004624 continue;
4625 }
4626 names->set(dest_pos++, name);
4627 }
4628 }
4629
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004630 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004631}
4632
4633
4634// Return the names of the local indexed properties.
4635// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004636RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004637 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004638 ASSERT(args.length() == 1);
4639 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004640 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004641 }
4642 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4643
4644 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004645 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004646 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004647 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004648}
4649
4650
4651// Return information on whether an object has a named or indexed interceptor.
4652// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004653RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004654 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004655 ASSERT(args.length() == 1);
4656 if (!args[0]->IsJSObject()) {
4657 return Smi::FromInt(0);
4658 }
4659 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4660
4661 int result = 0;
4662 if (obj->HasNamedInterceptor()) result |= 2;
4663 if (obj->HasIndexedInterceptor()) result |= 1;
4664
4665 return Smi::FromInt(result);
4666}
4667
4668
4669// Return property names from named interceptor.
4670// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004671RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004672 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004673 ASSERT(args.length() == 1);
4674 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4675
4676 if (obj->HasNamedInterceptor()) {
4677 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4678 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4679 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004680 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004681}
4682
4683
4684// Return element names from indexed interceptor.
4685// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004686RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004687 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004688 ASSERT(args.length() == 1);
4689 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4690
4691 if (obj->HasIndexedInterceptor()) {
4692 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4693 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4694 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004695 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004696}
4697
4698
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004699RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004700 ASSERT_EQ(args.length(), 1);
4701 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004702 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004703 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004704
4705 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004706 // Do access checks before going to the global object.
4707 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004708 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004709 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004710 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4711 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004712 }
4713
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004714 Handle<Object> proto(object->GetPrototype());
4715 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004716 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004717 object = Handle<JSObject>::cast(proto);
4718 }
4719
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004720 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4721 LOCAL_ONLY);
4722 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4723 // property array and since the result is mutable we have to create
4724 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004725 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004726 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004727 for (int i = 0; i < length; i++) {
4728 Object* entry = contents->get(i);
4729 if (entry->IsString()) {
4730 copy->set(i, entry);
4731 } else {
4732 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004733 HandleScope scope(isolate);
4734 Handle<Object> entry_handle(entry, isolate);
4735 Handle<Object> entry_str =
4736 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004737 copy->set(i, *entry_str);
4738 }
4739 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004740 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004741}
4742
4743
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004744RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004745 NoHandleAllocation ha;
4746 ASSERT(args.length() == 1);
4747
4748 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004749 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004750 it.AdvanceToArgumentsFrame();
4751 JavaScriptFrame* frame = it.frame();
4752
4753 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004754 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004755
4756 // Try to convert the key to an index. If successful and within
4757 // index return the the argument from the frame.
4758 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004759 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004760 return frame->GetParameter(index);
4761 }
4762
4763 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004764 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004765 bool exception = false;
4766 Handle<Object> converted =
4767 Execution::ToString(args.at<Object>(0), &exception);
4768 if (exception) return Failure::Exception();
4769 Handle<String> key = Handle<String>::cast(converted);
4770
4771 // Try to convert the string key into an array index.
4772 if (key->AsArrayIndex(&index)) {
4773 if (index < n) {
4774 return frame->GetParameter(index);
4775 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004776 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004777 }
4778 }
4779
4780 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004781 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4782 if (key->Equals(isolate->heap()->callee_symbol())) {
4783 Object* function = frame->function();
4784 if (function->IsJSFunction() &&
4785 JSFunction::cast(function)->shared()->strict_mode()) {
4786 return isolate->Throw(*isolate->factory()->NewTypeError(
4787 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4788 }
4789 return function;
4790 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004791
4792 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004793 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004794}
4795
4796
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004797RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004798 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004799
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004800 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004801 Handle<Object> object = args.at<Object>(0);
4802 if (object->IsJSObject()) {
4803 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004804 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004805 MaybeObject* ok = js_object->TransformToFastProperties(0);
4806 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004807 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004808 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004809 return *object;
4810}
4811
4812
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004813RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004814 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004815
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004816 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004817 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004818 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004819 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004820 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004821 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004822 return *object;
4823}
4824
4825
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004826RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004827 NoHandleAllocation ha;
4828 ASSERT(args.length() == 1);
4829
4830 return args[0]->ToBoolean();
4831}
4832
4833
4834// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4835// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004836RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004837 NoHandleAllocation ha;
4838
4839 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004840 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004841 HeapObject* heap_obj = HeapObject::cast(obj);
4842
4843 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004844 if (heap_obj->map()->is_undetectable()) {
4845 return isolate->heap()->undefined_symbol();
4846 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004847
4848 InstanceType instance_type = heap_obj->map()->instance_type();
4849 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004850 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004851 }
4852
4853 switch (instance_type) {
4854 case ODDBALL_TYPE:
4855 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004856 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004857 }
4858 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004859 return FLAG_harmony_typeof
4860 ? isolate->heap()->null_symbol()
4861 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004862 }
4863 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004864 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004865 case JS_FUNCTION_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004866 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004867 default:
4868 // For any kind of object not handled above, the spec rule for
4869 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004870 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004871 }
4872}
4873
4874
lrn@chromium.org25156de2010-04-06 13:10:27 +00004875static bool AreDigits(const char*s, int from, int to) {
4876 for (int i = from; i < to; i++) {
4877 if (s[i] < '0' || s[i] > '9') return false;
4878 }
4879
4880 return true;
4881}
4882
4883
4884static int ParseDecimalInteger(const char*s, int from, int to) {
4885 ASSERT(to - from < 10); // Overflow is not possible.
4886 ASSERT(from < to);
4887 int d = s[from] - '0';
4888
4889 for (int i = from + 1; i < to; i++) {
4890 d = 10 * d + (s[i] - '0');
4891 }
4892
4893 return d;
4894}
4895
4896
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004897RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004898 NoHandleAllocation ha;
4899 ASSERT(args.length() == 1);
4900 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004901 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004902
4903 // Fast case: short integer or some sorts of junk values.
4904 int len = subject->length();
4905 if (subject->IsSeqAsciiString()) {
4906 if (len == 0) return Smi::FromInt(0);
4907
4908 char const* data = SeqAsciiString::cast(subject)->GetChars();
4909 bool minus = (data[0] == '-');
4910 int start_pos = (minus ? 1 : 0);
4911
4912 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004913 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004914 } else if (data[start_pos] > '9') {
4915 // Fast check for a junk value. A valid string may start from a
4916 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4917 // the 'I' character ('Infinity'). All of that have codes not greater than
4918 // '9' except 'I'.
4919 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004920 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004921 }
4922 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4923 // The maximal/minimal smi has 10 digits. If the string has less digits we
4924 // know it will fit into the smi-data type.
4925 int d = ParseDecimalInteger(data, start_pos, len);
4926 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004927 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004928 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004929 } else if (!subject->HasHashCode() &&
4930 len <= String::kMaxArrayIndexSize &&
4931 (len == 1 || data[0] != '0')) {
4932 // String hash is not calculated yet but all the data are present.
4933 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004934 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004935#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004936 subject->Hash(); // Force hash calculation.
4937 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4938 static_cast<int>(hash));
4939#endif
4940 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004941 }
4942 return Smi::FromInt(d);
4943 }
4944 }
4945
4946 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004947 return isolate->heap()->NumberFromDouble(
4948 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004949}
4950
4951
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004952RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004953 NoHandleAllocation ha;
4954 ASSERT(args.length() == 1);
4955
4956 CONVERT_CHECKED(JSArray, codes, args[0]);
4957 int length = Smi::cast(codes->length())->value();
4958
4959 // Check if the string can be ASCII.
4960 int i;
4961 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004962 Object* element;
4963 { MaybeObject* maybe_element = codes->GetElement(i);
4964 // We probably can't get an exception here, but just in order to enforce
4965 // the checking of inputs in the runtime calls we check here.
4966 if (!maybe_element->ToObject(&element)) return maybe_element;
4967 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004968 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4969 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4970 break;
4971 }
4972
lrn@chromium.org303ada72010-10-27 09:33:13 +00004973 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004974 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004975 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004976 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004977 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004978 }
4979
lrn@chromium.org303ada72010-10-27 09:33:13 +00004980 Object* object = NULL;
4981 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004982 String* result = String::cast(object);
4983 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004984 Object* element;
4985 { MaybeObject* maybe_element = codes->GetElement(i);
4986 if (!maybe_element->ToObject(&element)) return maybe_element;
4987 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004988 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004989 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004990 }
4991 return result;
4992}
4993
4994
4995// kNotEscaped is generated by the following:
4996//
4997// #!/bin/perl
4998// for (my $i = 0; $i < 256; $i++) {
4999// print "\n" if $i % 16 == 0;
5000// my $c = chr($i);
5001// my $escaped = 1;
5002// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5003// print $escaped ? "0, " : "1, ";
5004// }
5005
5006
5007static bool IsNotEscaped(uint16_t character) {
5008 // Only for 8 bit characters, the rest are always escaped (in a different way)
5009 ASSERT(character < 256);
5010 static const char kNotEscaped[256] = {
5011 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5012 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5013 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5014 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5015 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5016 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5017 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5018 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5019 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5020 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5021 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5022 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5023 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5024 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5025 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5026 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5027 };
5028 return kNotEscaped[character] != 0;
5029}
5030
5031
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005032RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005033 const char hex_chars[] = "0123456789ABCDEF";
5034 NoHandleAllocation ha;
5035 ASSERT(args.length() == 1);
5036 CONVERT_CHECKED(String, source, args[0]);
5037
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005038 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005039
5040 int escaped_length = 0;
5041 int length = source->length();
5042 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005043 Access<StringInputBuffer> buffer(
5044 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005045 buffer->Reset(source);
5046 while (buffer->has_more()) {
5047 uint16_t character = buffer->GetNext();
5048 if (character >= 256) {
5049 escaped_length += 6;
5050 } else if (IsNotEscaped(character)) {
5051 escaped_length++;
5052 } else {
5053 escaped_length += 3;
5054 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005055 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005056 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005057 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005058 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005059 return Failure::OutOfMemoryException();
5060 }
5061 }
5062 }
5063 // No length change implies no change. Return original string if no change.
5064 if (escaped_length == length) {
5065 return source;
5066 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005067 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005068 { MaybeObject* maybe_o =
5069 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005070 if (!maybe_o->ToObject(&o)) return maybe_o;
5071 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005072 String* destination = String::cast(o);
5073 int dest_position = 0;
5074
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005075 Access<StringInputBuffer> buffer(
5076 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005077 buffer->Rewind();
5078 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005079 uint16_t chr = buffer->GetNext();
5080 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005081 destination->Set(dest_position, '%');
5082 destination->Set(dest_position+1, 'u');
5083 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5084 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5085 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5086 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005087 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005088 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005089 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005090 dest_position++;
5091 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005092 destination->Set(dest_position, '%');
5093 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5094 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005095 dest_position += 3;
5096 }
5097 }
5098 return destination;
5099}
5100
5101
5102static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5103 static const signed char kHexValue['g'] = {
5104 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5105 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5106 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5107 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5108 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5109 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5110 -1, 10, 11, 12, 13, 14, 15 };
5111
5112 if (character1 > 'f') return -1;
5113 int hi = kHexValue[character1];
5114 if (hi == -1) return -1;
5115 if (character2 > 'f') return -1;
5116 int lo = kHexValue[character2];
5117 if (lo == -1) return -1;
5118 return (hi << 4) + lo;
5119}
5120
5121
ager@chromium.org870a0b62008-11-04 11:43:05 +00005122static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005123 int i,
5124 int length,
5125 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005126 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005127 int32_t hi = 0;
5128 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005129 if (character == '%' &&
5130 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005131 source->Get(i + 1) == 'u' &&
5132 (hi = TwoDigitHex(source->Get(i + 2),
5133 source->Get(i + 3))) != -1 &&
5134 (lo = TwoDigitHex(source->Get(i + 4),
5135 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005136 *step = 6;
5137 return (hi << 8) + lo;
5138 } else if (character == '%' &&
5139 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005140 (lo = TwoDigitHex(source->Get(i + 1),
5141 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005142 *step = 3;
5143 return lo;
5144 } else {
5145 *step = 1;
5146 return character;
5147 }
5148}
5149
5150
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005151RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005152 NoHandleAllocation ha;
5153 ASSERT(args.length() == 1);
5154 CONVERT_CHECKED(String, source, args[0]);
5155
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005156 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005157
5158 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005159 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005160
5161 int unescaped_length = 0;
5162 for (int i = 0; i < length; unescaped_length++) {
5163 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005164 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005165 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005166 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005167 i += step;
5168 }
5169
5170 // No length change implies no change. Return original string if no change.
5171 if (unescaped_length == length)
5172 return source;
5173
lrn@chromium.org303ada72010-10-27 09:33:13 +00005174 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005175 { MaybeObject* maybe_o =
5176 ascii ?
5177 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5178 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005179 if (!maybe_o->ToObject(&o)) return maybe_o;
5180 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005181 String* destination = String::cast(o);
5182
5183 int dest_position = 0;
5184 for (int i = 0; i < length; dest_position++) {
5185 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005186 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005187 i += step;
5188 }
5189 return destination;
5190}
5191
5192
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005193static const unsigned int kQuoteTableLength = 128u;
5194
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005195static const int kJsonQuotesCharactersPerEntry = 8;
5196static const char* const JsonQuotes =
5197 "\\u0000 \\u0001 \\u0002 \\u0003 "
5198 "\\u0004 \\u0005 \\u0006 \\u0007 "
5199 "\\b \\t \\n \\u000b "
5200 "\\f \\r \\u000e \\u000f "
5201 "\\u0010 \\u0011 \\u0012 \\u0013 "
5202 "\\u0014 \\u0015 \\u0016 \\u0017 "
5203 "\\u0018 \\u0019 \\u001a \\u001b "
5204 "\\u001c \\u001d \\u001e \\u001f "
5205 " ! \\\" # "
5206 "$ % & ' "
5207 "( ) * + "
5208 ", - . / "
5209 "0 1 2 3 "
5210 "4 5 6 7 "
5211 "8 9 : ; "
5212 "< = > ? "
5213 "@ A B C "
5214 "D E F G "
5215 "H I J K "
5216 "L M N O "
5217 "P Q R S "
5218 "T U V W "
5219 "X Y Z [ "
5220 "\\\\ ] ^ _ "
5221 "` a b c "
5222 "d e f g "
5223 "h i j k "
5224 "l m n o "
5225 "p q r s "
5226 "t u v w "
5227 "x y z { "
5228 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005229
5230
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005231// For a string that is less than 32k characters it should always be
5232// possible to allocate it in new space.
5233static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5234
5235
5236// Doing JSON quoting cannot make the string more than this many times larger.
5237static const int kJsonQuoteWorstCaseBlowup = 6;
5238
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005239static const int kSpaceForQuotesAndComma = 3;
5240static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005241
5242// Covers the entire ASCII range (all other characters are unchanged by JSON
5243// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005244static const byte JsonQuoteLengths[kQuoteTableLength] = {
5245 6, 6, 6, 6, 6, 6, 6, 6,
5246 2, 2, 2, 6, 2, 2, 6, 6,
5247 6, 6, 6, 6, 6, 6, 6, 6,
5248 6, 6, 6, 6, 6, 6, 6, 6,
5249 1, 1, 2, 1, 1, 1, 1, 1,
5250 1, 1, 1, 1, 1, 1, 1, 1,
5251 1, 1, 1, 1, 1, 1, 1, 1,
5252 1, 1, 1, 1, 1, 1, 1, 1,
5253 1, 1, 1, 1, 1, 1, 1, 1,
5254 1, 1, 1, 1, 1, 1, 1, 1,
5255 1, 1, 1, 1, 1, 1, 1, 1,
5256 1, 1, 1, 1, 2, 1, 1, 1,
5257 1, 1, 1, 1, 1, 1, 1, 1,
5258 1, 1, 1, 1, 1, 1, 1, 1,
5259 1, 1, 1, 1, 1, 1, 1, 1,
5260 1, 1, 1, 1, 1, 1, 1, 1,
5261};
5262
5263
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005264template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005265MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005266
5267
5268template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005269MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5270 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005271}
5272
5273
5274template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005275MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5276 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005277}
5278
5279
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005280template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005281static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5282 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005283 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005284 const Char* read_cursor = characters.start();
5285 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005286 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005287 int quoted_length = kSpaceForQuotes;
5288 while (read_cursor < end) {
5289 Char c = *(read_cursor++);
5290 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5291 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005292 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005293 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005294 }
5295 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005296 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5297 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005298 Object* new_object;
5299 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005300 return new_alloc;
5301 }
5302 StringType* new_string = StringType::cast(new_object);
5303
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005304 Char* write_cursor = reinterpret_cast<Char*>(
5305 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005306 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005307 *(write_cursor++) = '"';
5308
5309 read_cursor = characters.start();
5310 while (read_cursor < end) {
5311 Char c = *(read_cursor++);
5312 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5313 *(write_cursor++) = c;
5314 } else {
5315 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5316 const char* replacement = JsonQuotes +
5317 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5318 for (int i = 0; i < len; i++) {
5319 *write_cursor++ = *replacement++;
5320 }
5321 }
5322 }
5323 *(write_cursor++) = '"';
5324 return new_string;
5325}
5326
5327
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005328template <typename SinkChar, typename SourceChar>
5329static inline SinkChar* WriteQuoteJsonString(
5330 Isolate* isolate,
5331 SinkChar* write_cursor,
5332 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005333 // SinkChar is only char if SourceChar is guaranteed to be char.
5334 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005335 const SourceChar* read_cursor = characters.start();
5336 const SourceChar* end = read_cursor + characters.length();
5337 *(write_cursor++) = '"';
5338 while (read_cursor < end) {
5339 SourceChar c = *(read_cursor++);
5340 if (sizeof(SourceChar) > 1u &&
5341 static_cast<unsigned>(c) >= kQuoteTableLength) {
5342 *(write_cursor++) = static_cast<SinkChar>(c);
5343 } else {
5344 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5345 const char* replacement = JsonQuotes +
5346 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5347 write_cursor[0] = replacement[0];
5348 if (len > 1) {
5349 write_cursor[1] = replacement[1];
5350 if (len > 2) {
5351 ASSERT(len == 6);
5352 write_cursor[2] = replacement[2];
5353 write_cursor[3] = replacement[3];
5354 write_cursor[4] = replacement[4];
5355 write_cursor[5] = replacement[5];
5356 }
5357 }
5358 write_cursor += len;
5359 }
5360 }
5361 *(write_cursor++) = '"';
5362 return write_cursor;
5363}
5364
5365
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005366template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005367static MaybeObject* QuoteJsonString(Isolate* isolate,
5368 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005369 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005370 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005371 int worst_case_length =
5372 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005373 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005374 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005375 }
5376
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005377 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5378 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005379 Object* new_object;
5380 if (!new_alloc->ToObject(&new_object)) {
5381 return new_alloc;
5382 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005383 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005384 // Even if our string is small enough to fit in new space we still have to
5385 // handle it being allocated in old space as may happen in the third
5386 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5387 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005388 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005389 }
5390 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005391 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005392
5393 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5394 Char* write_cursor = reinterpret_cast<Char*>(
5395 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005396 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005397 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5398 write_cursor,
5399 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005400 int final_length = static_cast<int>(
5401 write_cursor - reinterpret_cast<Char*>(
5402 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005403 isolate->heap()->new_space()->
5404 template ShrinkStringAtAllocationBoundary<StringType>(
5405 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005406 return new_string;
5407}
5408
5409
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005410RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005411 NoHandleAllocation ha;
5412 CONVERT_CHECKED(String, str, args[0]);
5413 if (!str->IsFlat()) {
5414 MaybeObject* try_flatten = str->TryFlatten();
5415 Object* flat;
5416 if (!try_flatten->ToObject(&flat)) {
5417 return try_flatten;
5418 }
5419 str = String::cast(flat);
5420 ASSERT(str->IsFlat());
5421 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005422 String::FlatContent flat = str->GetFlatContent();
5423 ASSERT(flat.IsFlat());
5424 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005425 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005426 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005427 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005428 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005429 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005430 }
5431}
5432
5433
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005434RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005435 NoHandleAllocation ha;
5436 CONVERT_CHECKED(String, str, args[0]);
5437 if (!str->IsFlat()) {
5438 MaybeObject* try_flatten = str->TryFlatten();
5439 Object* flat;
5440 if (!try_flatten->ToObject(&flat)) {
5441 return try_flatten;
5442 }
5443 str = String::cast(flat);
5444 ASSERT(str->IsFlat());
5445 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005446 String::FlatContent flat = str->GetFlatContent();
5447 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005448 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005449 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005450 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005451 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005452 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005453 }
5454}
5455
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005456
5457template <typename Char, typename StringType>
5458static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5459 FixedArray* array,
5460 int worst_case_length) {
5461 int length = array->length();
5462
5463 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5464 worst_case_length);
5465 Object* new_object;
5466 if (!new_alloc->ToObject(&new_object)) {
5467 return new_alloc;
5468 }
5469 if (!isolate->heap()->new_space()->Contains(new_object)) {
5470 // Even if our string is small enough to fit in new space we still have to
5471 // handle it being allocated in old space as may happen in the third
5472 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5473 // CEntryStub::GenerateCore.
5474 return isolate->heap()->undefined_value();
5475 }
5476 AssertNoAllocation no_gc;
5477 StringType* new_string = StringType::cast(new_object);
5478 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5479
5480 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5481 Char* write_cursor = reinterpret_cast<Char*>(
5482 new_string->address() + SeqAsciiString::kHeaderSize);
5483 *(write_cursor++) = '[';
5484 for (int i = 0; i < length; i++) {
5485 if (i != 0) *(write_cursor++) = ',';
5486 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005487 String::FlatContent content = str->GetFlatContent();
5488 ASSERT(content.IsFlat());
5489 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005490 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5491 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005492 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005493 } else {
5494 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5495 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005496 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005497 }
5498 }
5499 *(write_cursor++) = ']';
5500
5501 int final_length = static_cast<int>(
5502 write_cursor - reinterpret_cast<Char*>(
5503 new_string->address() + SeqAsciiString::kHeaderSize));
5504 isolate->heap()->new_space()->
5505 template ShrinkStringAtAllocationBoundary<StringType>(
5506 new_string, final_length);
5507 return new_string;
5508}
5509
5510
5511RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5512 NoHandleAllocation ha;
5513 ASSERT(args.length() == 1);
5514 CONVERT_CHECKED(JSArray, array, args[0]);
5515
5516 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5517 FixedArray* elements = FixedArray::cast(array->elements());
5518 int n = elements->length();
5519 bool ascii = true;
5520 int total_length = 0;
5521
5522 for (int i = 0; i < n; i++) {
5523 Object* elt = elements->get(i);
5524 if (!elt->IsString()) return isolate->heap()->undefined_value();
5525 String* element = String::cast(elt);
5526 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5527 total_length += element->length();
5528 if (ascii && element->IsTwoByteRepresentation()) {
5529 ascii = false;
5530 }
5531 }
5532
5533 int worst_case_length =
5534 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5535 + total_length * kJsonQuoteWorstCaseBlowup;
5536
5537 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5538 return isolate->heap()->undefined_value();
5539 }
5540
5541 if (ascii) {
5542 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5543 elements,
5544 worst_case_length);
5545 } else {
5546 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5547 elements,
5548 worst_case_length);
5549 }
5550}
5551
5552
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005553RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005554 NoHandleAllocation ha;
5555
5556 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005557 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005558
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005559 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005560
lrn@chromium.org25156de2010-04-06 13:10:27 +00005561 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005562 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005563 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005564}
5565
5566
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005567RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005568 NoHandleAllocation ha;
5569 CONVERT_CHECKED(String, str, args[0]);
5570
5571 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005572 double value = StringToDouble(isolate->unicode_cache(),
5573 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005574
5575 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005576 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005577}
5578
5579
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005580template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005581MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005582 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005583 String* s,
5584 int length,
5585 int input_string_length,
5586 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005587 // We try this twice, once with the assumption that the result is no longer
5588 // than the input and, if that assumption breaks, again with the exact
5589 // length. This may not be pretty, but it is nicer than what was here before
5590 // and I hereby claim my vaffel-is.
5591 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005592 // Allocate the resulting string.
5593 //
5594 // NOTE: This assumes that the upper/lower case of an ascii
5595 // character is also ascii. This is currently the case, but it
5596 // might break in the future if we implement more context and locale
5597 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005598 Object* o;
5599 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005600 ? isolate->heap()->AllocateRawAsciiString(length)
5601 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005602 if (!maybe_o->ToObject(&o)) return maybe_o;
5603 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005604 String* result = String::cast(o);
5605 bool has_changed_character = false;
5606
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005607 // Convert all characters to upper case, assuming that they will fit
5608 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005609 Access<StringInputBuffer> buffer(
5610 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005611 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005612 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005613 // We can assume that the string is not empty
5614 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005615 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005616 bool has_next = buffer->has_more();
5617 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005618 int char_length = mapping->get(current, next, chars);
5619 if (char_length == 0) {
5620 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005621 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005622 i++;
5623 } else if (char_length == 1) {
5624 // Common case: converting the letter resulted in one character.
5625 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005626 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005627 has_changed_character = true;
5628 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005629 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005630 // We've assumed that the result would be as long as the
5631 // input but here is a character that converts to several
5632 // characters. No matter, we calculate the exact length
5633 // of the result and try the whole thing again.
5634 //
5635 // Note that this leaves room for optimization. We could just
5636 // memcpy what we already have to the result string. Also,
5637 // the result string is the last object allocated we could
5638 // "realloc" it and probably, in the vast majority of cases,
5639 // extend the existing string to be able to hold the full
5640 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005641 int next_length = 0;
5642 if (has_next) {
5643 next_length = mapping->get(next, 0, chars);
5644 if (next_length == 0) next_length = 1;
5645 }
5646 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005647 while (buffer->has_more()) {
5648 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005649 // NOTE: we use 0 as the next character here because, while
5650 // the next character may affect what a character converts to,
5651 // it does not in any case affect the length of what it convert
5652 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005653 int char_length = mapping->get(current, 0, chars);
5654 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005655 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005656 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005657 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005658 return Failure::OutOfMemoryException();
5659 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005660 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005661 // Try again with the real length.
5662 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005663 } else {
5664 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005665 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005666 i++;
5667 }
5668 has_changed_character = true;
5669 }
5670 current = next;
5671 }
5672 if (has_changed_character) {
5673 return result;
5674 } else {
5675 // If we didn't actually change anything in doing the conversion
5676 // we simple return the result and let the converted string
5677 // become garbage; there is no reason to keep two identical strings
5678 // alive.
5679 return s;
5680 }
5681}
5682
5683
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005684namespace {
5685
lrn@chromium.org303ada72010-10-27 09:33:13 +00005686static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5687
5688
5689// Given a word and two range boundaries returns a word with high bit
5690// set in every byte iff the corresponding input byte was strictly in
5691// the range (m, n). All the other bits in the result are cleared.
5692// This function is only useful when it can be inlined and the
5693// boundaries are statically known.
5694// Requires: all bytes in the input word and the boundaries must be
5695// ascii (less than 0x7F).
5696static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5697 // Every byte in an ascii string is less than or equal to 0x7F.
5698 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5699 // Use strict inequalities since in edge cases the function could be
5700 // further simplified.
5701 ASSERT(0 < m && m < n && n < 0x7F);
5702 // Has high bit set in every w byte less than n.
5703 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5704 // Has high bit set in every w byte greater than m.
5705 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5706 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5707}
5708
5709
5710enum AsciiCaseConversion {
5711 ASCII_TO_LOWER,
5712 ASCII_TO_UPPER
5713};
5714
5715
5716template <AsciiCaseConversion dir>
5717struct FastAsciiConverter {
5718 static bool Convert(char* dst, char* src, int length) {
5719#ifdef DEBUG
5720 char* saved_dst = dst;
5721 char* saved_src = src;
5722#endif
5723 // We rely on the distance between upper and lower case letters
5724 // being a known power of 2.
5725 ASSERT('a' - 'A' == (1 << 5));
5726 // Boundaries for the range of input characters than require conversion.
5727 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5728 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5729 bool changed = false;
5730 char* const limit = src + length;
5731#ifdef V8_HOST_CAN_READ_UNALIGNED
5732 // Process the prefix of the input that requires no conversion one
5733 // (machine) word at a time.
5734 while (src <= limit - sizeof(uintptr_t)) {
5735 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5736 if (AsciiRangeMask(w, lo, hi) != 0) {
5737 changed = true;
5738 break;
5739 }
5740 *reinterpret_cast<uintptr_t*>(dst) = w;
5741 src += sizeof(uintptr_t);
5742 dst += sizeof(uintptr_t);
5743 }
5744 // Process the remainder of the input performing conversion when
5745 // required one word at a time.
5746 while (src <= limit - sizeof(uintptr_t)) {
5747 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5748 uintptr_t m = AsciiRangeMask(w, lo, hi);
5749 // The mask has high (7th) bit set in every byte that needs
5750 // conversion and we know that the distance between cases is
5751 // 1 << 5.
5752 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5753 src += sizeof(uintptr_t);
5754 dst += sizeof(uintptr_t);
5755 }
5756#endif
5757 // Process the last few bytes of the input (or the whole input if
5758 // unaligned access is not supported).
5759 while (src < limit) {
5760 char c = *src;
5761 if (lo < c && c < hi) {
5762 c ^= (1 << 5);
5763 changed = true;
5764 }
5765 *dst = c;
5766 ++src;
5767 ++dst;
5768 }
5769#ifdef DEBUG
5770 CheckConvert(saved_dst, saved_src, length, changed);
5771#endif
5772 return changed;
5773 }
5774
5775#ifdef DEBUG
5776 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5777 bool expected_changed = false;
5778 for (int i = 0; i < length; i++) {
5779 if (dst[i] == src[i]) continue;
5780 expected_changed = true;
5781 if (dir == ASCII_TO_LOWER) {
5782 ASSERT('A' <= src[i] && src[i] <= 'Z');
5783 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5784 } else {
5785 ASSERT(dir == ASCII_TO_UPPER);
5786 ASSERT('a' <= src[i] && src[i] <= 'z');
5787 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5788 }
5789 }
5790 ASSERT(expected_changed == changed);
5791 }
5792#endif
5793};
5794
5795
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005796struct ToLowerTraits {
5797 typedef unibrow::ToLowercase UnibrowConverter;
5798
lrn@chromium.org303ada72010-10-27 09:33:13 +00005799 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005800};
5801
5802
5803struct ToUpperTraits {
5804 typedef unibrow::ToUppercase UnibrowConverter;
5805
lrn@chromium.org303ada72010-10-27 09:33:13 +00005806 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005807};
5808
5809} // namespace
5810
5811
5812template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005813MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005814 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005815 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005816 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005817 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005818 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005819 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005820
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005821 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005822 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005823 if (length == 0) return s;
5824
5825 // Simpler handling of ascii strings.
5826 //
5827 // NOTE: This assumes that the upper/lower case of an ascii
5828 // character is also ascii. This is currently the case, but it
5829 // might break in the future if we implement more context and locale
5830 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005831 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005832 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005833 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005834 if (!maybe_o->ToObject(&o)) return maybe_o;
5835 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005836 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005837 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005838 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005839 return has_changed_character ? result : s;
5840 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005841
lrn@chromium.org303ada72010-10-27 09:33:13 +00005842 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005843 { MaybeObject* maybe_answer =
5844 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005845 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5846 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005847 if (answer->IsSmi()) {
5848 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005849 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005850 ConvertCaseHelper(isolate,
5851 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005852 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5853 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005854 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005855 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005856}
5857
5858
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005859RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005860 return ConvertCase<ToLowerTraits>(
5861 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005862}
5863
5864
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005865RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005866 return ConvertCase<ToUpperTraits>(
5867 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005868}
5869
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005870
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005871static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5872 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5873}
5874
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005875
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005876RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005877 NoHandleAllocation ha;
5878 ASSERT(args.length() == 3);
5879
5880 CONVERT_CHECKED(String, s, args[0]);
5881 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5882 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5883
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005884 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005885 int length = s->length();
5886
5887 int left = 0;
5888 if (trimLeft) {
5889 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5890 left++;
5891 }
5892 }
5893
5894 int right = length;
5895 if (trimRight) {
5896 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5897 right--;
5898 }
5899 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005900 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005901}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005902
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005903
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005904void FindAsciiStringIndices(Vector<const char> subject,
5905 char pattern,
5906 ZoneList<int>* indices,
5907 unsigned int limit) {
5908 ASSERT(limit > 0);
5909 // Collect indices of pattern in subject using memchr.
5910 // Stop after finding at most limit values.
5911 const char* subject_start = reinterpret_cast<const char*>(subject.start());
5912 const char* subject_end = subject_start + subject.length();
5913 const char* pos = subject_start;
5914 while (limit > 0) {
5915 pos = reinterpret_cast<const char*>(
5916 memchr(pos, pattern, subject_end - pos));
5917 if (pos == NULL) return;
5918 indices->Add(static_cast<int>(pos - subject_start));
5919 pos++;
5920 limit--;
5921 }
5922}
5923
5924
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005925template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005926void FindStringIndices(Isolate* isolate,
5927 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005928 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005929 ZoneList<int>* indices,
5930 unsigned int limit) {
5931 ASSERT(limit > 0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005932 // Collect indices of pattern in subject.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005933 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005934 int pattern_length = pattern.length();
5935 int index = 0;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005936 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005937 while (limit > 0) {
5938 index = search.Search(subject, index);
5939 if (index < 0) return;
5940 indices->Add(index);
5941 index += pattern_length;
5942 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005943 }
5944}
5945
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005946
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005947RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005948 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005949 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005950 CONVERT_ARG_CHECKED(String, subject, 0);
5951 CONVERT_ARG_CHECKED(String, pattern, 1);
5952 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5953
5954 int subject_length = subject->length();
5955 int pattern_length = pattern->length();
5956 RUNTIME_ASSERT(pattern_length > 0);
5957
5958 // The limit can be very large (0xffffffffu), but since the pattern
5959 // isn't empty, we can never create more parts than ~half the length
5960 // of the subject.
5961
5962 if (!subject->IsFlat()) FlattenString(subject);
5963
5964 static const int kMaxInitialListCapacity = 16;
5965
danno@chromium.org40cb8782011-05-25 07:58:50 +00005966 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005967
5968 // Find (up to limit) indices of separator and end-of-string in subject
5969 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5970 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005971 if (!pattern->IsFlat()) FlattenString(pattern);
5972
5973 // No allocation block.
5974 {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005975 AssertNoAllocation no_gc;
5976 String::FlatContent subject_content = subject->GetFlatContent();
5977 String::FlatContent pattern_content = pattern->GetFlatContent();
5978 ASSERT(subject_content.IsFlat());
5979 ASSERT(pattern_content.IsFlat());
5980 if (subject_content.IsAscii()) {
5981 Vector<const char> subject_vector = subject_content.ToAsciiVector();
5982 if (pattern_content.IsAscii()) {
5983 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005984 if (pattern_vector.length() == 1) {
5985 FindAsciiStringIndices(subject_vector,
5986 pattern_vector[0],
5987 &indices,
5988 limit);
5989 } else {
5990 FindStringIndices(isolate,
5991 subject_vector,
5992 pattern_vector,
5993 &indices,
5994 limit);
5995 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005996 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005997 FindStringIndices(isolate,
5998 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005999 pattern_content.ToUC16Vector(),
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006000 &indices,
6001 limit);
6002 }
6003 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006004 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006005 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006006 FindStringIndices(isolate,
6007 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006008 pattern_content.ToAsciiVector(),
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006009 &indices,
6010 limit);
6011 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006012 FindStringIndices(isolate,
6013 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006014 pattern_content.ToUC16Vector(),
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006015 &indices,
6016 limit);
6017 }
6018 }
6019 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006020
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006021 if (static_cast<uint32_t>(indices.length()) < limit) {
6022 indices.Add(subject_length);
6023 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006024
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006025 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006026
6027 // Create JSArray of substrings separated by separator.
6028 int part_count = indices.length();
6029
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006030 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006031 result->set_length(Smi::FromInt(part_count));
6032
6033 ASSERT(result->HasFastElements());
6034
6035 if (part_count == 1 && indices.at(0) == subject_length) {
6036 FixedArray::cast(result->elements())->set(0, *subject);
6037 return *result;
6038 }
6039
6040 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6041 int part_start = 0;
6042 for (int i = 0; i < part_count; i++) {
6043 HandleScope local_loop_handle;
6044 int part_end = indices.at(i);
6045 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006046 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006047 elements->set(i, *substring);
6048 part_start = part_end + pattern_length;
6049 }
6050
6051 return *result;
6052}
6053
6054
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006055// Copies ascii characters to the given fixed array looking up
6056// one-char strings in the cache. Gives up on the first char that is
6057// not in the cache and fills the remainder with smi zeros. Returns
6058// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006059static int CopyCachedAsciiCharsToArray(Heap* heap,
6060 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006061 FixedArray* elements,
6062 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006063 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006064 FixedArray* ascii_cache = heap->single_character_string_cache();
6065 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006066 int i;
6067 for (i = 0; i < length; ++i) {
6068 Object* value = ascii_cache->get(chars[i]);
6069 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006070 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006071 elements->set(i, value, SKIP_WRITE_BARRIER);
6072 }
6073 if (i < length) {
6074 ASSERT(Smi::FromInt(0) == 0);
6075 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6076 }
6077#ifdef DEBUG
6078 for (int j = 0; j < length; ++j) {
6079 Object* element = elements->get(j);
6080 ASSERT(element == Smi::FromInt(0) ||
6081 (element->IsString() && String::cast(element)->LooksValid()));
6082 }
6083#endif
6084 return i;
6085}
6086
6087
6088// Converts a String to JSArray.
6089// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006090RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006091 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006092 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006093 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006094 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006095
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006096 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006097 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006098
6099 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006100 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006101 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006102 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006103 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006104 { MaybeObject* maybe_obj =
6105 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006106 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6107 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006108 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006109 String::FlatContent content = s->GetFlatContent();
6110 if (content.IsAscii()) {
6111 Vector<const char> chars = content.ToAsciiVector();
6112 // Note, this will initialize all elements (not only the prefix)
6113 // to prevent GC from seeing partially initialized array.
6114 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6115 chars.start(),
6116 *elements,
6117 length);
6118 } else {
6119 MemsetPointer(elements->data_start(),
6120 isolate->heap()->undefined_value(),
6121 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006122 }
6123 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006124 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006125 }
6126 for (int i = position; i < length; ++i) {
6127 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6128 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006129 }
6130
6131#ifdef DEBUG
6132 for (int i = 0; i < length; ++i) {
6133 ASSERT(String::cast(elements->get(i))->length() == 1);
6134 }
6135#endif
6136
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006137 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006138}
6139
6140
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006141RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006142 NoHandleAllocation ha;
6143 ASSERT(args.length() == 1);
6144 CONVERT_CHECKED(String, value, args[0]);
6145 return value->ToObject();
6146}
6147
6148
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006149bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006150 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006151 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006152 return char_length == 0;
6153}
6154
6155
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006156RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006157 NoHandleAllocation ha;
6158 ASSERT(args.length() == 1);
6159
6160 Object* number = args[0];
6161 RUNTIME_ASSERT(number->IsNumber());
6162
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006163 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006164}
6165
6166
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006167RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006168 NoHandleAllocation ha;
6169 ASSERT(args.length() == 1);
6170
6171 Object* number = args[0];
6172 RUNTIME_ASSERT(number->IsNumber());
6173
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006174 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006175}
6176
6177
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006178RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006179 NoHandleAllocation ha;
6180 ASSERT(args.length() == 1);
6181
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006182 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006183
6184 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6185 if (number > 0 && number <= Smi::kMaxValue) {
6186 return Smi::FromInt(static_cast<int>(number));
6187 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006188 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006189}
6190
6191
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006192RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006193 NoHandleAllocation ha;
6194 ASSERT(args.length() == 1);
6195
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006196 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006197
6198 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6199 if (number > 0 && number <= Smi::kMaxValue) {
6200 return Smi::FromInt(static_cast<int>(number));
6201 }
6202
6203 double double_value = DoubleToInteger(number);
6204 // Map both -0 and +0 to +0.
6205 if (double_value == 0) double_value = 0;
6206
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006207 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006208}
6209
6210
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006211RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006212 NoHandleAllocation ha;
6213 ASSERT(args.length() == 1);
6214
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006215 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006216 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006217}
6218
6219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006220RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006221 NoHandleAllocation ha;
6222 ASSERT(args.length() == 1);
6223
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006224 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006225
6226 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6227 if (number > 0 && number <= Smi::kMaxValue) {
6228 return Smi::FromInt(static_cast<int>(number));
6229 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006230 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006231}
6232
6233
ager@chromium.org870a0b62008-11-04 11:43:05 +00006234// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6235// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006236RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006237 NoHandleAllocation ha;
6238 ASSERT(args.length() == 1);
6239
6240 Object* obj = args[0];
6241 if (obj->IsSmi()) {
6242 return obj;
6243 }
6244 if (obj->IsHeapNumber()) {
6245 double value = HeapNumber::cast(obj)->value();
6246 int int_value = FastD2I(value);
6247 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6248 return Smi::FromInt(int_value);
6249 }
6250 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006251 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006252}
6253
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006254
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006255RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006256 NoHandleAllocation ha;
6257 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006258 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006259}
6260
6261
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006262RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006263 NoHandleAllocation ha;
6264 ASSERT(args.length() == 2);
6265
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006266 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6267 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006268 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006269}
6270
6271
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006272RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006273 NoHandleAllocation ha;
6274 ASSERT(args.length() == 2);
6275
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006276 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6277 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006278 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006279}
6280
6281
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006282RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006283 NoHandleAllocation ha;
6284 ASSERT(args.length() == 2);
6285
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006286 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6287 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006288 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006289}
6290
6291
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006292RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006293 NoHandleAllocation ha;
6294 ASSERT(args.length() == 1);
6295
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006296 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006297 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006298}
6299
6300
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006301RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006302 NoHandleAllocation ha;
6303 ASSERT(args.length() == 0);
6304
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006305 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006306}
6307
6308
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006309RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006310 NoHandleAllocation ha;
6311 ASSERT(args.length() == 2);
6312
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006313 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6314 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006315 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006316}
6317
6318
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006319RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006320 NoHandleAllocation ha;
6321 ASSERT(args.length() == 2);
6322
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006323 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6324 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006325
ager@chromium.org3811b432009-10-28 14:53:37 +00006326 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006327 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006328 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006329}
6330
6331
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006332RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006333 NoHandleAllocation ha;
6334 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006335 CONVERT_CHECKED(String, str1, args[0]);
6336 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006337 isolate->counters()->string_add_runtime()->Increment();
6338 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006339}
6340
6341
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006342template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006343static inline void StringBuilderConcatHelper(String* special,
6344 sinkchar* sink,
6345 FixedArray* fixed_array,
6346 int array_length) {
6347 int position = 0;
6348 for (int i = 0; i < array_length; i++) {
6349 Object* element = fixed_array->get(i);
6350 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006351 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006352 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006353 int pos;
6354 int len;
6355 if (encoded_slice > 0) {
6356 // Position and length encoded in one smi.
6357 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6358 len = StringBuilderSubstringLength::decode(encoded_slice);
6359 } else {
6360 // Position and length encoded in two smis.
6361 Object* obj = fixed_array->get(++i);
6362 ASSERT(obj->IsSmi());
6363 pos = Smi::cast(obj)->value();
6364 len = -encoded_slice;
6365 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006366 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006367 sink + position,
6368 pos,
6369 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006370 position += len;
6371 } else {
6372 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006373 int element_length = string->length();
6374 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006375 position += element_length;
6376 }
6377 }
6378}
6379
6380
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006381RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006382 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006383 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006384 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006385 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006386 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006387 return Failure::OutOfMemoryException();
6388 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006389 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006390 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006391
6392 // This assumption is used by the slice encoding in one or two smis.
6393 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6394
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006395 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006396 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006397 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006398 }
6399 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006400 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006401 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006402 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006403
6404 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006405 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006406 } else if (array_length == 1) {
6407 Object* first = fixed_array->get(0);
6408 if (first->IsString()) return first;
6409 }
6410
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006411 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006412 int position = 0;
6413 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006414 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006415 Object* elt = fixed_array->get(i);
6416 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006417 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006418 int smi_value = Smi::cast(elt)->value();
6419 int pos;
6420 int len;
6421 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006422 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006423 pos = StringBuilderSubstringPosition::decode(smi_value);
6424 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006425 } else {
6426 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006427 len = -smi_value;
6428 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006429 i++;
6430 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006431 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006432 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006433 Object* next_smi = fixed_array->get(i);
6434 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006435 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006436 }
6437 pos = Smi::cast(next_smi)->value();
6438 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006439 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006440 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006441 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006442 ASSERT(pos >= 0);
6443 ASSERT(len >= 0);
6444 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006445 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006446 }
6447 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006448 } else if (elt->IsString()) {
6449 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006450 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006451 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006452 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006453 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006454 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006455 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006456 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006457 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006458 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006459 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006460 return Failure::OutOfMemoryException();
6461 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006462 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006463 }
6464
6465 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006466 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006467
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006468 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006469 { MaybeObject* maybe_object =
6470 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006471 if (!maybe_object->ToObject(&object)) return maybe_object;
6472 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006473 SeqAsciiString* answer = SeqAsciiString::cast(object);
6474 StringBuilderConcatHelper(special,
6475 answer->GetChars(),
6476 fixed_array,
6477 array_length);
6478 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006479 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006480 { MaybeObject* maybe_object =
6481 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006482 if (!maybe_object->ToObject(&object)) return maybe_object;
6483 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006484 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6485 StringBuilderConcatHelper(special,
6486 answer->GetChars(),
6487 fixed_array,
6488 array_length);
6489 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006490 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006491}
6492
6493
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006494RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006495 NoHandleAllocation ha;
6496 ASSERT(args.length() == 3);
6497 CONVERT_CHECKED(JSArray, array, args[0]);
6498 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006499 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006500 return Failure::OutOfMemoryException();
6501 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006502 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006503 CONVERT_CHECKED(String, separator, args[2]);
6504
6505 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006506 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006507 }
6508 FixedArray* fixed_array = FixedArray::cast(array->elements());
6509 if (fixed_array->length() < array_length) {
6510 array_length = fixed_array->length();
6511 }
6512
6513 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006514 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006515 } else if (array_length == 1) {
6516 Object* first = fixed_array->get(0);
6517 if (first->IsString()) return first;
6518 }
6519
6520 int separator_length = separator->length();
6521 int max_nof_separators =
6522 (String::kMaxLength + separator_length - 1) / separator_length;
6523 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006524 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006525 return Failure::OutOfMemoryException();
6526 }
6527 int length = (array_length - 1) * separator_length;
6528 for (int i = 0; i < array_length; i++) {
6529 Object* element_obj = fixed_array->get(i);
6530 if (!element_obj->IsString()) {
6531 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006532 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006533 }
6534 String* element = String::cast(element_obj);
6535 int increment = element->length();
6536 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006537 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006538 return Failure::OutOfMemoryException();
6539 }
6540 length += increment;
6541 }
6542
6543 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006544 { MaybeObject* maybe_object =
6545 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006546 if (!maybe_object->ToObject(&object)) return maybe_object;
6547 }
6548 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6549
6550 uc16* sink = answer->GetChars();
6551#ifdef DEBUG
6552 uc16* end = sink + length;
6553#endif
6554
6555 String* first = String::cast(fixed_array->get(0));
6556 int first_length = first->length();
6557 String::WriteToFlat(first, sink, 0, first_length);
6558 sink += first_length;
6559
6560 for (int i = 1; i < array_length; i++) {
6561 ASSERT(sink + separator_length <= end);
6562 String::WriteToFlat(separator, sink, 0, separator_length);
6563 sink += separator_length;
6564
6565 String* element = String::cast(fixed_array->get(i));
6566 int element_length = element->length();
6567 ASSERT(sink + element_length <= end);
6568 String::WriteToFlat(element, sink, 0, element_length);
6569 sink += element_length;
6570 }
6571 ASSERT(sink == end);
6572
6573 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6574 return answer;
6575}
6576
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006577template <typename Char>
6578static void JoinSparseArrayWithSeparator(FixedArray* elements,
6579 int elements_length,
6580 uint32_t array_length,
6581 String* separator,
6582 Vector<Char> buffer) {
6583 int previous_separator_position = 0;
6584 int separator_length = separator->length();
6585 int cursor = 0;
6586 for (int i = 0; i < elements_length; i += 2) {
6587 int position = NumberToInt32(elements->get(i));
6588 String* string = String::cast(elements->get(i + 1));
6589 int string_length = string->length();
6590 if (string->length() > 0) {
6591 while (previous_separator_position < position) {
6592 String::WriteToFlat<Char>(separator, &buffer[cursor],
6593 0, separator_length);
6594 cursor += separator_length;
6595 previous_separator_position++;
6596 }
6597 String::WriteToFlat<Char>(string, &buffer[cursor],
6598 0, string_length);
6599 cursor += string->length();
6600 }
6601 }
6602 if (separator_length > 0) {
6603 // Array length must be representable as a signed 32-bit number,
6604 // otherwise the total string length would have been too large.
6605 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6606 int last_array_index = static_cast<int>(array_length - 1);
6607 while (previous_separator_position < last_array_index) {
6608 String::WriteToFlat<Char>(separator, &buffer[cursor],
6609 0, separator_length);
6610 cursor += separator_length;
6611 previous_separator_position++;
6612 }
6613 }
6614 ASSERT(cursor <= buffer.length());
6615}
6616
6617
6618RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6619 NoHandleAllocation ha;
6620 ASSERT(args.length() == 3);
6621 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6622 RUNTIME_ASSERT(elements_array->HasFastElements());
6623 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6624 CONVERT_CHECKED(String, separator, args[2]);
6625 // elements_array is fast-mode JSarray of alternating positions
6626 // (increasing order) and strings.
6627 // array_length is length of original array (used to add separators);
6628 // separator is string to put between elements. Assumed to be non-empty.
6629
6630 // Find total length of join result.
6631 int string_length = 0;
6632 bool is_ascii = true;
6633 int max_string_length = SeqAsciiString::kMaxLength;
6634 bool overflow = false;
6635 CONVERT_NUMBER_CHECKED(int, elements_length,
6636 Int32, elements_array->length());
6637 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6638 FixedArray* elements = FixedArray::cast(elements_array->elements());
6639 for (int i = 0; i < elements_length; i += 2) {
6640 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6641 CONVERT_CHECKED(String, string, elements->get(i + 1));
6642 int length = string->length();
6643 if (is_ascii && !string->IsAsciiRepresentation()) {
6644 is_ascii = false;
6645 max_string_length = SeqTwoByteString::kMaxLength;
6646 }
6647 if (length > max_string_length ||
6648 max_string_length - length < string_length) {
6649 overflow = true;
6650 break;
6651 }
6652 string_length += length;
6653 }
6654 int separator_length = separator->length();
6655 if (!overflow && separator_length > 0) {
6656 if (array_length <= 0x7fffffffu) {
6657 int separator_count = static_cast<int>(array_length) - 1;
6658 int remaining_length = max_string_length - string_length;
6659 if ((remaining_length / separator_length) >= separator_count) {
6660 string_length += separator_length * (array_length - 1);
6661 } else {
6662 // Not room for the separators within the maximal string length.
6663 overflow = true;
6664 }
6665 } else {
6666 // Nonempty separator and at least 2^31-1 separators necessary
6667 // means that the string is too large to create.
6668 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6669 overflow = true;
6670 }
6671 }
6672 if (overflow) {
6673 // Throw OutOfMemory exception for creating too large a string.
6674 V8::FatalProcessOutOfMemory("Array join result too large.");
6675 }
6676
6677 if (is_ascii) {
6678 MaybeObject* result_allocation =
6679 isolate->heap()->AllocateRawAsciiString(string_length);
6680 if (result_allocation->IsFailure()) return result_allocation;
6681 SeqAsciiString* result_string =
6682 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6683 JoinSparseArrayWithSeparator<char>(elements,
6684 elements_length,
6685 array_length,
6686 separator,
6687 Vector<char>(result_string->GetChars(),
6688 string_length));
6689 return result_string;
6690 } else {
6691 MaybeObject* result_allocation =
6692 isolate->heap()->AllocateRawTwoByteString(string_length);
6693 if (result_allocation->IsFailure()) return result_allocation;
6694 SeqTwoByteString* result_string =
6695 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6696 JoinSparseArrayWithSeparator<uc16>(elements,
6697 elements_length,
6698 array_length,
6699 separator,
6700 Vector<uc16>(result_string->GetChars(),
6701 string_length));
6702 return result_string;
6703 }
6704}
6705
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006706
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006707RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006708 NoHandleAllocation ha;
6709 ASSERT(args.length() == 2);
6710
6711 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6712 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006713 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006714}
6715
6716
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006717RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006718 NoHandleAllocation ha;
6719 ASSERT(args.length() == 2);
6720
6721 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6722 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006723 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006724}
6725
6726
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006727RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006728 NoHandleAllocation ha;
6729 ASSERT(args.length() == 2);
6730
6731 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6732 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006733 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006734}
6735
6736
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006737RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006738 NoHandleAllocation ha;
6739 ASSERT(args.length() == 1);
6740
6741 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006742 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006743}
6744
6745
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006746RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006747 NoHandleAllocation ha;
6748 ASSERT(args.length() == 2);
6749
6750 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6751 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006752 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006753}
6754
6755
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006756RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006757 NoHandleAllocation ha;
6758 ASSERT(args.length() == 2);
6759
6760 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6761 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006762 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006763}
6764
6765
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006766RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006767 NoHandleAllocation ha;
6768 ASSERT(args.length() == 2);
6769
6770 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6771 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006772 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006773}
6774
6775
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006776RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006777 NoHandleAllocation ha;
6778 ASSERT(args.length() == 2);
6779
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006780 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6781 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006782 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6783 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6784 if (x == y) return Smi::FromInt(EQUAL);
6785 Object* result;
6786 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6787 result = Smi::FromInt(EQUAL);
6788 } else {
6789 result = Smi::FromInt(NOT_EQUAL);
6790 }
6791 return result;
6792}
6793
6794
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006795RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006796 NoHandleAllocation ha;
6797 ASSERT(args.length() == 2);
6798
6799 CONVERT_CHECKED(String, x, args[0]);
6800 CONVERT_CHECKED(String, y, args[1]);
6801
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006802 bool not_equal = !x->Equals(y);
6803 // This is slightly convoluted because the value that signifies
6804 // equality is 0 and inequality is 1 so we have to negate the result
6805 // from String::Equals.
6806 ASSERT(not_equal == 0 || not_equal == 1);
6807 STATIC_CHECK(EQUAL == 0);
6808 STATIC_CHECK(NOT_EQUAL == 1);
6809 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006810}
6811
6812
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006813RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006814 NoHandleAllocation ha;
6815 ASSERT(args.length() == 3);
6816
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006817 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6818 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006819 if (isnan(x) || isnan(y)) return args[2];
6820 if (x == y) return Smi::FromInt(EQUAL);
6821 if (isless(x, y)) return Smi::FromInt(LESS);
6822 return Smi::FromInt(GREATER);
6823}
6824
6825
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006826// Compare two Smis as if they were converted to strings and then
6827// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006828RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006829 NoHandleAllocation ha;
6830 ASSERT(args.length() == 2);
6831
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006832 // Extract the integer values from the Smis.
6833 CONVERT_CHECKED(Smi, x, args[0]);
6834 CONVERT_CHECKED(Smi, y, args[1]);
6835 int x_value = x->value();
6836 int y_value = y->value();
6837
6838 // If the integers are equal so are the string representations.
6839 if (x_value == y_value) return Smi::FromInt(EQUAL);
6840
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006841 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006842 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006843 if (x_value == 0 || y_value == 0)
6844 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006845
ager@chromium.org32912102009-01-16 10:38:43 +00006846 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006847 // smallest because the char code of '-' is less than the char code
6848 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006849
6850 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
6851 // architectures using 32-bit Smis.
6852 uint32_t x_scaled = x_value;
6853 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006854 if (x_value < 0 || y_value < 0) {
6855 if (y_value >= 0) return Smi::FromInt(LESS);
6856 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006857 x_scaled = -x_value;
6858 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006859 }
6860
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006861 static const uint32_t kPowersOf10[] = {
6862 1, 10, 100, 1000, 10*1000, 100*1000,
6863 1000*1000, 10*1000*1000, 100*1000*1000,
6864 1000*1000*1000
6865 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006866
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006867 // If the integers have the same number of decimal digits they can be
6868 // compared directly as the numeric order is the same as the
6869 // lexicographic order. If one integer has fewer digits, it is scaled
6870 // by some power of 10 to have the same number of digits as the longer
6871 // integer. If the scaled integers are equal it means the shorter
6872 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006873
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006874 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
6875 int x_log2 = IntegerLog2(x_scaled);
6876 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
6877 x_log10 -= x_scaled < kPowersOf10[x_log10];
6878
6879 int y_log2 = IntegerLog2(y_scaled);
6880 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
6881 y_log10 -= y_scaled < kPowersOf10[y_log10];
6882
6883 int tie = EQUAL;
6884
6885 if (x_log10 < y_log10) {
6886 // X has fewer digits. We would like to simply scale up X but that
6887 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
6888 // be scaled up to 9_000_000_000. So we scale up by the next
6889 // smallest power and scale down Y to drop one digit. It is OK to
6890 // drop one digit from the longer integer since the final digit is
6891 // past the length of the shorter integer.
6892 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
6893 y_scaled /= 10;
6894 tie = LESS;
6895 } else if (y_log10 < x_log10) {
6896 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
6897 x_scaled /= 10;
6898 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006899 }
6900
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006901 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
6902 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
6903 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006904}
6905
6906
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006907static Object* StringInputBufferCompare(RuntimeState* state,
6908 String* x,
6909 String* y) {
6910 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6911 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006912 bufx.Reset(x);
6913 bufy.Reset(y);
6914 while (bufx.has_more() && bufy.has_more()) {
6915 int d = bufx.GetNext() - bufy.GetNext();
6916 if (d < 0) return Smi::FromInt(LESS);
6917 else if (d > 0) return Smi::FromInt(GREATER);
6918 }
6919
6920 // x is (non-trivial) prefix of y:
6921 if (bufy.has_more()) return Smi::FromInt(LESS);
6922 // y is prefix of x:
6923 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6924}
6925
6926
6927static Object* FlatStringCompare(String* x, String* y) {
6928 ASSERT(x->IsFlat());
6929 ASSERT(y->IsFlat());
6930 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6931 int prefix_length = x->length();
6932 if (y->length() < prefix_length) {
6933 prefix_length = y->length();
6934 equal_prefix_result = Smi::FromInt(GREATER);
6935 } else if (y->length() > prefix_length) {
6936 equal_prefix_result = Smi::FromInt(LESS);
6937 }
6938 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006939 String::FlatContent x_content = x->GetFlatContent();
6940 String::FlatContent y_content = y->GetFlatContent();
6941 if (x_content.IsAscii()) {
6942 Vector<const char> x_chars = x_content.ToAsciiVector();
6943 if (y_content.IsAscii()) {
6944 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006945 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006946 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006947 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006948 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6949 }
6950 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006951 Vector<const uc16> x_chars = x_content.ToUC16Vector();
6952 if (y_content.IsAscii()) {
6953 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006954 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6955 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006956 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006957 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6958 }
6959 }
6960 Object* result;
6961 if (r == 0) {
6962 result = equal_prefix_result;
6963 } else {
6964 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6965 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006966 ASSERT(result ==
6967 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006968 return result;
6969}
6970
6971
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006972RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006973 NoHandleAllocation ha;
6974 ASSERT(args.length() == 2);
6975
6976 CONVERT_CHECKED(String, x, args[0]);
6977 CONVERT_CHECKED(String, y, args[1]);
6978
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006979 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006980
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006981 // A few fast case tests before we flatten.
6982 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006983 if (y->length() == 0) {
6984 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006985 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006986 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006987 return Smi::FromInt(LESS);
6988 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006989
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006990 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006991 if (d < 0) return Smi::FromInt(LESS);
6992 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006993
lrn@chromium.org303ada72010-10-27 09:33:13 +00006994 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006995 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006996 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6997 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006998 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006999 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7000 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007001
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007002 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007003 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007004}
7005
7006
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007007RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007008 NoHandleAllocation ha;
7009 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007010 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007011
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007012 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007013 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007014}
7015
7016
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007017RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007018 NoHandleAllocation ha;
7019 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007020 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007021
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007022 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007023 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007024}
7025
7026
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007027RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007028 NoHandleAllocation ha;
7029 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007030 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007031
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007032 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007033 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007034}
7035
7036
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007037static const double kPiDividedBy4 = 0.78539816339744830962;
7038
7039
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007040RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007041 NoHandleAllocation ha;
7042 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007043 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007044
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007045 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7046 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007047 double result;
7048 if (isinf(x) && isinf(y)) {
7049 // Make sure that the result in case of two infinite arguments
7050 // is a multiple of Pi / 4. The sign of the result is determined
7051 // by the first argument (x) and the sign of the second argument
7052 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007053 int multiplier = (x < 0) ? -1 : 1;
7054 if (y < 0) multiplier *= 3;
7055 result = multiplier * kPiDividedBy4;
7056 } else {
7057 result = atan2(x, y);
7058 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007059 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007060}
7061
7062
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007063RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007064 NoHandleAllocation ha;
7065 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007066 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007067
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007068 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007069 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007070}
7071
7072
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007073RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007074 NoHandleAllocation ha;
7075 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007076 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007077
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007078 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007079 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007080}
7081
7082
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007083RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007084 NoHandleAllocation ha;
7085 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007086 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007087
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007088 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007089 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007090}
7091
7092
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007093RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007094 NoHandleAllocation ha;
7095 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007096 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007097
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007098 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007099 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007100}
7101
7102
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007103RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007104 NoHandleAllocation ha;
7105 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007106 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007107
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007108 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007109 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007110}
7111
7112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007113RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007114 NoHandleAllocation ha;
7115 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007116 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007117
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007118 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007119
7120 // If the second argument is a smi, it is much faster to call the
7121 // custom powi() function than the generic pow().
7122 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007123 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007124 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007125 }
7126
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007127 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007128 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007129}
7130
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007131// Fast version of Math.pow if we know that y is not an integer and
7132// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007133RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007134 NoHandleAllocation ha;
7135 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007136 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7137 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007138 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007139 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007140 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007141 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007142 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007143 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007144 }
7145}
7146
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007147
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007148RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007149 NoHandleAllocation ha;
7150 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007151 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007152
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007153 if (!args[0]->IsHeapNumber()) {
7154 // Must be smi. Return the argument unchanged for all the other types
7155 // to make fuzz-natives test happy.
7156 return args[0];
7157 }
7158
7159 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7160
7161 double value = number->value();
7162 int exponent = number->get_exponent();
7163 int sign = number->get_sign();
7164
danno@chromium.org160a7b02011-04-18 15:51:38 +00007165 if (exponent < -1) {
7166 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7167 if (sign) return isolate->heap()->minus_zero_value();
7168 return Smi::FromInt(0);
7169 }
7170
7171 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7172 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7173 // agument holds for 32-bit smis).
7174 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007175 return Smi::FromInt(static_cast<int>(value + 0.5));
7176 }
7177
7178 // If the magnitude is big enough, there's no place for fraction part. If we
7179 // try to add 0.5 to this number, 1.0 will be added instead.
7180 if (exponent >= 52) {
7181 return number;
7182 }
7183
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007184 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007185
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007186 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007187 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007188}
7189
7190
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007191RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007192 NoHandleAllocation ha;
7193 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007194 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007195
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007196 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007197 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007198}
7199
7200
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007201RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007202 NoHandleAllocation ha;
7203 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007204 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007205
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007206 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007207 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007208}
7209
7210
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007211RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007212 NoHandleAllocation ha;
7213 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007214 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007215
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007216 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007217 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007218}
7219
7220
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007221static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007222 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7223 181, 212, 243, 273, 304, 334};
7224 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7225 182, 213, 244, 274, 305, 335};
7226
7227 year += month / 12;
7228 month %= 12;
7229 if (month < 0) {
7230 year--;
7231 month += 12;
7232 }
7233
7234 ASSERT(month >= 0);
7235 ASSERT(month < 12);
7236
7237 // year_delta is an arbitrary number such that:
7238 // a) year_delta = -1 (mod 400)
7239 // b) year + year_delta > 0 for years in the range defined by
7240 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7241 // Jan 1 1970. This is required so that we don't run into integer
7242 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007243 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007244 // operations.
7245 static const int year_delta = 399999;
7246 static const int base_day = 365 * (1970 + year_delta) +
7247 (1970 + year_delta) / 4 -
7248 (1970 + year_delta) / 100 +
7249 (1970 + year_delta) / 400;
7250
7251 int year1 = year + year_delta;
7252 int day_from_year = 365 * year1 +
7253 year1 / 4 -
7254 year1 / 100 +
7255 year1 / 400 -
7256 base_day;
7257
7258 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007259 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007260 }
7261
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007262 return day_from_year + day_from_month_leap[month] + day - 1;
7263}
7264
7265
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007266RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007267 NoHandleAllocation ha;
7268 ASSERT(args.length() == 3);
7269
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007270 CONVERT_SMI_ARG_CHECKED(year, 0);
7271 CONVERT_SMI_ARG_CHECKED(month, 1);
7272 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007273
7274 return Smi::FromInt(MakeDay(year, month, date));
7275}
7276
7277
7278static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7279static const int kDaysIn4Years = 4 * 365 + 1;
7280static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7281static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7282static const int kDays1970to2000 = 30 * 365 + 7;
7283static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7284 kDays1970to2000;
7285static const int kYearsOffset = 400000;
7286
7287static const char kDayInYear[] = {
7288 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7289 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7290 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7291 22, 23, 24, 25, 26, 27, 28,
7292 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7293 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7294 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7295 22, 23, 24, 25, 26, 27, 28, 29, 30,
7296 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7297 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7298 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7299 22, 23, 24, 25, 26, 27, 28, 29, 30,
7300 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7301 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7302 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7303 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7304 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7305 22, 23, 24, 25, 26, 27, 28, 29, 30,
7306 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7307 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7308 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7309 22, 23, 24, 25, 26, 27, 28, 29, 30,
7310 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7311 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7312
7313 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7314 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7315 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7316 22, 23, 24, 25, 26, 27, 28,
7317 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7318 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7319 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7320 22, 23, 24, 25, 26, 27, 28, 29, 30,
7321 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7322 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7323 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7324 22, 23, 24, 25, 26, 27, 28, 29, 30,
7325 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7326 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7327 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7328 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7329 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7330 22, 23, 24, 25, 26, 27, 28, 29, 30,
7331 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7332 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7333 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7334 22, 23, 24, 25, 26, 27, 28, 29, 30,
7335 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7336 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7337
7338 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7339 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7340 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7341 22, 23, 24, 25, 26, 27, 28, 29,
7342 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7343 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7344 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7345 22, 23, 24, 25, 26, 27, 28, 29, 30,
7346 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7347 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7348 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7349 22, 23, 24, 25, 26, 27, 28, 29, 30,
7350 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7351 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7352 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7353 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7354 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7355 22, 23, 24, 25, 26, 27, 28, 29, 30,
7356 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7357 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7358 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7359 22, 23, 24, 25, 26, 27, 28, 29, 30,
7360 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7361 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7362
7363 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7364 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7365 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7366 22, 23, 24, 25, 26, 27, 28,
7367 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7368 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7369 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7370 22, 23, 24, 25, 26, 27, 28, 29, 30,
7371 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7372 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7373 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7374 22, 23, 24, 25, 26, 27, 28, 29, 30,
7375 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7376 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7377 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7378 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7379 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7380 22, 23, 24, 25, 26, 27, 28, 29, 30,
7381 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7382 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7383 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7384 22, 23, 24, 25, 26, 27, 28, 29, 30,
7385 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7386 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7387
7388static const char kMonthInYear[] = {
7389 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7390 0, 0, 0, 0, 0, 0,
7391 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7392 1, 1, 1,
7393 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7394 2, 2, 2, 2, 2, 2,
7395 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7396 3, 3, 3, 3, 3,
7397 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7398 4, 4, 4, 4, 4, 4,
7399 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7400 5, 5, 5, 5, 5,
7401 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7402 6, 6, 6, 6, 6, 6,
7403 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7404 7, 7, 7, 7, 7, 7,
7405 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7406 8, 8, 8, 8, 8,
7407 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7408 9, 9, 9, 9, 9, 9,
7409 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7410 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7411 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7412 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7413
7414 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7415 0, 0, 0, 0, 0, 0,
7416 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7417 1, 1, 1,
7418 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7419 2, 2, 2, 2, 2, 2,
7420 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7421 3, 3, 3, 3, 3,
7422 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7423 4, 4, 4, 4, 4, 4,
7424 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7425 5, 5, 5, 5, 5,
7426 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7427 6, 6, 6, 6, 6, 6,
7428 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7429 7, 7, 7, 7, 7, 7,
7430 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7431 8, 8, 8, 8, 8,
7432 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7433 9, 9, 9, 9, 9, 9,
7434 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7435 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7436 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7437 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7438
7439 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7440 0, 0, 0, 0, 0, 0,
7441 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7442 1, 1, 1, 1,
7443 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7444 2, 2, 2, 2, 2, 2,
7445 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7446 3, 3, 3, 3, 3,
7447 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7448 4, 4, 4, 4, 4, 4,
7449 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7450 5, 5, 5, 5, 5,
7451 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7452 6, 6, 6, 6, 6, 6,
7453 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7454 7, 7, 7, 7, 7, 7,
7455 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7456 8, 8, 8, 8, 8,
7457 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7458 9, 9, 9, 9, 9, 9,
7459 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7460 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7461 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7462 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7463
7464 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7465 0, 0, 0, 0, 0, 0,
7466 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7467 1, 1, 1,
7468 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7469 2, 2, 2, 2, 2, 2,
7470 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7471 3, 3, 3, 3, 3,
7472 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7473 4, 4, 4, 4, 4, 4,
7474 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7475 5, 5, 5, 5, 5,
7476 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7477 6, 6, 6, 6, 6, 6,
7478 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7479 7, 7, 7, 7, 7, 7,
7480 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7481 8, 8, 8, 8, 8,
7482 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7483 9, 9, 9, 9, 9, 9,
7484 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7485 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7486 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7487 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7488
7489
7490// This function works for dates from 1970 to 2099.
7491static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007492 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007493#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007494 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007495#endif
7496
7497 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7498 date %= kDaysIn4Years;
7499
7500 month = kMonthInYear[date];
7501 day = kDayInYear[date];
7502
7503 ASSERT(MakeDay(year, month, day) == save_date);
7504}
7505
7506
7507static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007508 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007509#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007510 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007511#endif
7512
7513 date += kDaysOffset;
7514 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7515 date %= kDaysIn400Years;
7516
7517 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7518
7519 date--;
7520 int yd1 = date / kDaysIn100Years;
7521 date %= kDaysIn100Years;
7522 year += 100 * yd1;
7523
7524 date++;
7525 int yd2 = date / kDaysIn4Years;
7526 date %= kDaysIn4Years;
7527 year += 4 * yd2;
7528
7529 date--;
7530 int yd3 = date / 365;
7531 date %= 365;
7532 year += yd3;
7533
7534 bool is_leap = (!yd1 || yd2) && !yd3;
7535
7536 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007537 ASSERT(is_leap || (date >= 0));
7538 ASSERT((date < 365) || (is_leap && (date < 366)));
7539 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7540 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7541 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007542
7543 if (is_leap) {
7544 day = kDayInYear[2*365 + 1 + date];
7545 month = kMonthInYear[2*365 + 1 + date];
7546 } else {
7547 day = kDayInYear[date];
7548 month = kMonthInYear[date];
7549 }
7550
7551 ASSERT(MakeDay(year, month, day) == save_date);
7552}
7553
7554
7555static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007556 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007557 if (date >= 0 && date < 32 * kDaysIn4Years) {
7558 DateYMDFromTimeAfter1970(date, year, month, day);
7559 } else {
7560 DateYMDFromTimeSlow(date, year, month, day);
7561 }
7562}
7563
7564
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007565RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007566 NoHandleAllocation ha;
7567 ASSERT(args.length() == 2);
7568
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007569 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007570 CONVERT_CHECKED(JSArray, res_array, args[1]);
7571
7572 int year, month, day;
7573 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7574
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007575 RUNTIME_ASSERT(res_array->elements()->map() ==
7576 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007577 FixedArray* elms = FixedArray::cast(res_array->elements());
7578 RUNTIME_ASSERT(elms->length() == 3);
7579
7580 elms->set(0, Smi::FromInt(year));
7581 elms->set(1, Smi::FromInt(month));
7582 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007583
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007584 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007585}
7586
7587
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007588RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007589 HandleScope scope(isolate);
7590 ASSERT(args.length() == 3);
7591
7592 Handle<JSFunction> callee = args.at<JSFunction>(0);
7593 Object** parameters = reinterpret_cast<Object**>(args[1]);
7594 const int argument_count = Smi::cast(args[2])->value();
7595
7596 Handle<JSObject> result =
7597 isolate->factory()->NewArgumentsObject(callee, argument_count);
7598 // Allocate the elements if needed.
7599 int parameter_count = callee->shared()->formal_parameter_count();
7600 if (argument_count > 0) {
7601 if (parameter_count > 0) {
7602 int mapped_count = Min(argument_count, parameter_count);
7603 Handle<FixedArray> parameter_map =
7604 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7605 parameter_map->set_map(
7606 isolate->heap()->non_strict_arguments_elements_map());
7607
7608 Handle<Map> old_map(result->map());
7609 Handle<Map> new_map =
7610 isolate->factory()->CopyMapDropTransitions(old_map);
7611 new_map->set_elements_kind(JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
7612
7613 result->set_map(*new_map);
7614 result->set_elements(*parameter_map);
7615
7616 // Store the context and the arguments array at the beginning of the
7617 // parameter map.
7618 Handle<Context> context(isolate->context());
7619 Handle<FixedArray> arguments =
7620 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7621 parameter_map->set(0, *context);
7622 parameter_map->set(1, *arguments);
7623
7624 // Loop over the actual parameters backwards.
7625 int index = argument_count - 1;
7626 while (index >= mapped_count) {
7627 // These go directly in the arguments array and have no
7628 // corresponding slot in the parameter map.
7629 arguments->set(index, *(parameters - index - 1));
7630 --index;
7631 }
7632
7633 ScopeInfo<> scope_info(callee->shared()->scope_info());
7634 while (index >= 0) {
7635 // Detect duplicate names to the right in the parameter list.
7636 Handle<String> name = scope_info.parameter_name(index);
7637 int context_slot_count = scope_info.number_of_context_slots();
7638 bool duplicate = false;
7639 for (int j = index + 1; j < parameter_count; ++j) {
7640 if (scope_info.parameter_name(j).is_identical_to(name)) {
7641 duplicate = true;
7642 break;
7643 }
7644 }
7645
7646 if (duplicate) {
7647 // This goes directly in the arguments array with a hole in the
7648 // parameter map.
7649 arguments->set(index, *(parameters - index - 1));
7650 parameter_map->set_the_hole(index + 2);
7651 } else {
7652 // The context index goes in the parameter map with a hole in the
7653 // arguments array.
7654 int context_index = -1;
7655 for (int j = Context::MIN_CONTEXT_SLOTS;
7656 j < context_slot_count;
7657 ++j) {
7658 if (scope_info.context_slot_name(j).is_identical_to(name)) {
7659 context_index = j;
7660 break;
7661 }
7662 }
7663 ASSERT(context_index >= 0);
7664 arguments->set_the_hole(index);
7665 parameter_map->set(index + 2, Smi::FromInt(context_index));
7666 }
7667
7668 --index;
7669 }
7670 } else {
7671 // If there is no aliasing, the arguments object elements are not
7672 // special in any way.
7673 Handle<FixedArray> elements =
7674 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7675 result->set_elements(*elements);
7676 for (int i = 0; i < argument_count; ++i) {
7677 elements->set(i, *(parameters - i - 1));
7678 }
7679 }
7680 }
7681 return *result;
7682}
7683
7684
7685RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007686 NoHandleAllocation ha;
7687 ASSERT(args.length() == 3);
7688
7689 JSFunction* callee = JSFunction::cast(args[0]);
7690 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007691 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007692
lrn@chromium.org303ada72010-10-27 09:33:13 +00007693 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007694 { MaybeObject* maybe_result =
7695 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007696 if (!maybe_result->ToObject(&result)) return maybe_result;
7697 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007698 // Allocate the elements if needed.
7699 if (length > 0) {
7700 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007701 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007702 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007703 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7704 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007705
7706 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007707 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007708 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007709 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007710
7711 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007712 for (int i = 0; i < length; i++) {
7713 array->set(i, *--parameters, mode);
7714 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007715 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007716 }
7717 return result;
7718}
7719
7720
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007721RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007722 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007723 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007724 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007725 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007726 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007727
whesse@chromium.org7b260152011-06-20 15:33:18 +00007728 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007729 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007730 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007731 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007732 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7733 context,
7734 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007735 return *result;
7736}
7737
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007738
7739static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7740 int* total_argc) {
7741 // Find frame containing arguments passed to the caller.
7742 JavaScriptFrameIterator it;
7743 JavaScriptFrame* frame = it.frame();
7744 List<JSFunction*> functions(2);
7745 frame->GetFunctions(&functions);
7746 if (functions.length() > 1) {
7747 int inlined_frame_index = functions.length() - 1;
7748 JSFunction* inlined_function = functions[inlined_frame_index];
7749 int args_count = inlined_function->shared()->formal_parameter_count();
7750 ScopedVector<SlotRef> args_slots(args_count);
7751 SlotRef::ComputeSlotMappingForArguments(frame,
7752 inlined_frame_index,
7753 &args_slots);
7754
7755 *total_argc = bound_argc + args_count;
7756 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7757 for (int i = 0; i < args_count; i++) {
7758 Handle<Object> val = args_slots[i].GetValue();
7759 param_data[bound_argc + i] = val.location();
7760 }
7761 return param_data;
7762 } else {
7763 it.AdvanceToArgumentsFrame();
7764 frame = it.frame();
7765 int args_count = frame->ComputeParametersCount();
7766
7767 *total_argc = bound_argc + args_count;
7768 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7769 for (int i = 0; i < args_count; i++) {
7770 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7771 param_data[bound_argc + i] = val.location();
7772 }
7773 return param_data;
7774 }
7775}
7776
7777
7778RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007779 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007780 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007781 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007782 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007783
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007784 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007785 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007786 int bound_argc = 0;
7787 if (!args[1]->IsNull()) {
7788 CONVERT_ARG_CHECKED(JSArray, params, 1);
7789 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007790 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007791 bound_argc = Smi::cast(params->length())->value();
7792 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007793
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007794 int total_argc = 0;
7795 SmartPointer<Object**> param_data =
7796 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007797 for (int i = 0; i < bound_argc; i++) {
7798 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007799 param_data[i] = val.location();
7800 }
7801
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007802 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007803 Handle<Object> result =
7804 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007805 if (exception) {
7806 return Failure::Exception();
7807 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007808
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007809 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007810 return *result;
7811}
7812
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007813
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007814static void TrySettingInlineConstructStub(Isolate* isolate,
7815 Handle<JSFunction> function) {
7816 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007817 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007818 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007819 }
7820 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007821 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007822 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007823 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007824 function->shared()->set_construct_stub(
7825 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007826 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007827 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007828}
7829
7830
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007831RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007832 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007833 ASSERT(args.length() == 1);
7834
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007835 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007836
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007837 // If the constructor isn't a proper function we throw a type error.
7838 if (!constructor->IsJSFunction()) {
7839 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7840 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007841 isolate->factory()->NewTypeError("not_constructor", arguments);
7842 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007843 }
7844
7845 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007846
7847 // If function should not have prototype, construction is not allowed. In this
7848 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007849 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007850 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7851 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007852 isolate->factory()->NewTypeError("not_constructor", arguments);
7853 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007854 }
7855
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007856#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007857 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007858 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007859 if (debug->StepInActive()) {
7860 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007861 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007862#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007863
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007864 if (function->has_initial_map()) {
7865 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007866 // The 'Function' function ignores the receiver object when
7867 // called using 'new' and creates a new JSFunction object that
7868 // is returned. The receiver object is only used for error
7869 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007870 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007871 // allocate JSFunctions since it does not properly initialize
7872 // the shared part of the function. Since the receiver is
7873 // ignored anyway, we use the global object as the receiver
7874 // instead of a new JSFunction object. This way, errors are
7875 // reported the same way whether or not 'Function' is called
7876 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007877 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007878 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007879 }
7880
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007881 // The function should be compiled for the optimization hints to be
7882 // available. We cannot use EnsureCompiled because that forces a
7883 // compilation through the shared function info which makes it
7884 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007885 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007886 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007887
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007888 if (!function->has_initial_map() &&
7889 shared->IsInobjectSlackTrackingInProgress()) {
7890 // The tracking is already in progress for another function. We can only
7891 // track one initial_map at a time, so we force the completion before the
7892 // function is called as a constructor for the first time.
7893 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007894 }
7895
7896 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007897 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7898 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007899 // Delay setting the stub if inobject slack tracking is in progress.
7900 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007901 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007902 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007903
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007904 isolate->counters()->constructed_objects()->Increment();
7905 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007906
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007907 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007908}
7909
7910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007911RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007912 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007913 ASSERT(args.length() == 1);
7914
7915 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7916 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007917 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007918
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007919 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007920}
7921
7922
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007923RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007924 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007925 ASSERT(args.length() == 1);
7926
7927 Handle<JSFunction> function = args.at<JSFunction>(0);
7928#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007929 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007930 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007931 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007932 PrintF("]\n");
7933 }
7934#endif
7935
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007936 // Compile the target function. Here we compile using CompileLazyInLoop in
7937 // order to get the optimized version. This helps code like delta-blue
7938 // that calls performance-critical routines through constructors. A
7939 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7940 // direct call. Since the in-loop tracking takes place through CallICs
7941 // this means that things called through constructors are never known to
7942 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007943 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007944 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007945 return Failure::Exception();
7946 }
7947
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007948 // All done. Return the compiled code.
7949 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007950 return function->code();
7951}
7952
7953
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007954RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007955 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007956 ASSERT(args.length() == 1);
7957 Handle<JSFunction> function = args.at<JSFunction>(0);
7958 // If the function is not optimizable or debugger is active continue using the
7959 // code from the full compiler.
7960 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007961 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007962 if (FLAG_trace_opt) {
7963 PrintF("[failed to optimize ");
7964 function->PrintName();
7965 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7966 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007967 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007968 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007969 function->ReplaceCode(function->shared()->code());
7970 return function->code();
7971 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007972 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007973 return function->code();
7974 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007975 if (FLAG_trace_opt) {
7976 PrintF("[failed to optimize ");
7977 function->PrintName();
7978 PrintF(": optimized compilation failed]\n");
7979 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007980 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007981 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007982}
7983
7984
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007985RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007986 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007987 ASSERT(args.length() == 1);
7988 RUNTIME_ASSERT(args[0]->IsSmi());
7989 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007990 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007991 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7992 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007993 int frames = deoptimizer->output_count();
7994
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007995 deoptimizer->MaterializeHeapNumbers();
7996 delete deoptimizer;
7997
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007998 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007999 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008000 for (int i = 0; i < frames - 1; i++) it.Advance();
8001 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008002
8003 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008004 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008005 Handle<Object> arguments;
8006 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008007 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008008 if (arguments.is_null()) {
8009 // FunctionGetArguments can't throw an exception, so cast away the
8010 // doubt with an assert.
8011 arguments = Handle<Object>(
8012 Accessors::FunctionGetArguments(*function,
8013 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008014 ASSERT(*arguments != isolate->heap()->null_value());
8015 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008016 }
8017 frame->SetExpression(i, *arguments);
8018 }
8019 }
8020
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008021 if (type == Deoptimizer::EAGER) {
8022 RUNTIME_ASSERT(function->IsOptimized());
8023 } else {
8024 RUNTIME_ASSERT(!function->IsOptimized());
8025 }
8026
8027 // Avoid doing too much work when running with --always-opt and keep
8028 // the optimized code around.
8029 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008030 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008031 }
8032
8033 // Count the number of optimized activations of the function.
8034 int activations = 0;
8035 while (!it.done()) {
8036 JavaScriptFrame* frame = it.frame();
8037 if (frame->is_optimized() && frame->function() == *function) {
8038 activations++;
8039 }
8040 it.Advance();
8041 }
8042
8043 // TODO(kasperl): For now, we cannot support removing the optimized
8044 // code when we have recursive invocations of the same function.
8045 if (activations == 0) {
8046 if (FLAG_trace_deopt) {
8047 PrintF("[removing optimized code for: ");
8048 function->PrintName();
8049 PrintF("]\n");
8050 }
8051 function->ReplaceCode(function->shared()->code());
8052 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008053 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008054}
8055
8056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008057RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008058 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008059 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008060 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008061}
8062
8063
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008064RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008065 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008066 ASSERT(args.length() == 1);
8067 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008068 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008069
8070 Deoptimizer::DeoptimizeFunction(*function);
8071
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008072 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008073}
8074
8075
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008076RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8077#if defined(USE_SIMULATOR)
8078 return isolate->heap()->true_value();
8079#else
8080 return isolate->heap()->false_value();
8081#endif
8082}
8083
8084
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008085RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8086 HandleScope scope(isolate);
8087 ASSERT(args.length() == 1);
8088 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8089 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8090 function->MarkForLazyRecompilation();
8091 return isolate->heap()->undefined_value();
8092}
8093
8094
lrn@chromium.org1c092762011-05-09 09:42:16 +00008095RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8096 HandleScope scope(isolate);
8097 ASSERT(args.length() == 1);
8098 if (!V8::UseCrankshaft()) {
8099 return Smi::FromInt(4); // 4 == "never".
8100 }
8101 if (FLAG_always_opt) {
8102 return Smi::FromInt(3); // 3 == "always".
8103 }
8104 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8105 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8106 : Smi::FromInt(2); // 2 == "no".
8107}
8108
8109
8110RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8111 HandleScope scope(isolate);
8112 ASSERT(args.length() == 1);
8113 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8114 return Smi::FromInt(function->shared()->opt_count());
8115}
8116
8117
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008118RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008119 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008120 ASSERT(args.length() == 1);
8121 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8122
8123 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008124 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008125
8126 // We have hit a back edge in an unoptimized frame for a function that was
8127 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008128 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008129 // Keep track of whether we've succeeded in optimizing.
8130 bool succeeded = unoptimized->optimizable();
8131 if (succeeded) {
8132 // If we are trying to do OSR when there are already optimized
8133 // activations of the function, it means (a) the function is directly or
8134 // indirectly recursive and (b) an optimized invocation has been
8135 // deoptimized so that we are currently in an unoptimized activation.
8136 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008137 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008138 while (succeeded && !it.done()) {
8139 JavaScriptFrame* frame = it.frame();
8140 succeeded = !frame->is_optimized() || frame->function() != *function;
8141 it.Advance();
8142 }
8143 }
8144
8145 int ast_id = AstNode::kNoNumber;
8146 if (succeeded) {
8147 // The top JS function is this one, the PC is somewhere in the
8148 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008149 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008150 JavaScriptFrame* frame = it.frame();
8151 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008152 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008153 ASSERT(unoptimized->contains(frame->pc()));
8154
8155 // Use linear search of the unoptimized code's stack check table to find
8156 // the AST id matching the PC.
8157 Address start = unoptimized->instruction_start();
8158 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008159 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008160 uint32_t table_length = Memory::uint32_at(table_cursor);
8161 table_cursor += kIntSize;
8162 for (unsigned i = 0; i < table_length; ++i) {
8163 // Table entries are (AST id, pc offset) pairs.
8164 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8165 if (pc_offset == target_pc_offset) {
8166 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8167 break;
8168 }
8169 table_cursor += 2 * kIntSize;
8170 }
8171 ASSERT(ast_id != AstNode::kNoNumber);
8172 if (FLAG_trace_osr) {
8173 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8174 function->PrintName();
8175 PrintF("]\n");
8176 }
8177
8178 // Try to compile the optimized code. A true return value from
8179 // CompileOptimized means that compilation succeeded, not necessarily
8180 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008181 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
8182 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008183 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8184 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008185 if (data->OsrPcOffset()->value() >= 0) {
8186 if (FLAG_trace_osr) {
8187 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008188 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008189 }
8190 ASSERT(data->OsrAstId()->value() == ast_id);
8191 } else {
8192 // We may never generate the desired OSR entry if we emit an
8193 // early deoptimize.
8194 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008195 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008196 } else {
8197 succeeded = false;
8198 }
8199 }
8200
8201 // Revert to the original stack checks in the original unoptimized code.
8202 if (FLAG_trace_osr) {
8203 PrintF("[restoring original stack checks in ");
8204 function->PrintName();
8205 PrintF("]\n");
8206 }
8207 StackCheckStub check_stub;
8208 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008209 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008210 Deoptimizer::RevertStackCheckCode(*unoptimized,
8211 *check_code,
8212 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008213
8214 // Allow OSR only at nesting level zero again.
8215 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8216
8217 // If the optimization attempt succeeded, return the AST id tagged as a
8218 // smi. This tells the builtin that we need to translate the unoptimized
8219 // frame to an optimized one.
8220 if (succeeded) {
8221 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8222 return Smi::FromInt(ast_id);
8223 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008224 if (function->IsMarkedForLazyRecompilation()) {
8225 function->ReplaceCode(function->shared()->code());
8226 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008227 return Smi::FromInt(-1);
8228 }
8229}
8230
8231
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008232RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008233 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008234 ASSERT(args.length() == 1);
8235 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8236 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8237}
8238
8239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008240RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008241 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008242 ASSERT(args.length() == 1);
8243 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8244 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8245}
8246
8247
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008248RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008249 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008250 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008251
kasper.lund7276f142008-07-30 08:49:36 +00008252 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00008253 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008254 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008255 { MaybeObject* maybe_result =
8256 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008257 if (!maybe_result->ToObject(&result)) return maybe_result;
8258 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008259
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008260 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008261
kasper.lund7276f142008-07-30 08:49:36 +00008262 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008263}
8264
lrn@chromium.org303ada72010-10-27 09:33:13 +00008265
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008266RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8267 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008268 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008269 JSObject* extension_object;
8270 if (args[0]->IsJSObject()) {
8271 extension_object = JSObject::cast(args[0]);
8272 } else {
8273 // Convert the object to a proper JavaScript object.
8274 MaybeObject* maybe_js_object = args[0]->ToObject();
8275 if (!maybe_js_object->To(&extension_object)) {
8276 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8277 HandleScope scope(isolate);
8278 Handle<Object> handle = args.at<Object>(0);
8279 Handle<Object> result =
8280 isolate->factory()->NewTypeError("with_expression",
8281 HandleVector(&handle, 1));
8282 return isolate->Throw(*result);
8283 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008284 return maybe_js_object;
8285 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008286 }
8287 }
8288
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008289 JSFunction* function;
8290 if (args[1]->IsSmi()) {
8291 // A smi sentinel indicates a context nested inside global code rather
8292 // than some function. There is a canonical empty function that can be
8293 // gotten from the global context.
8294 function = isolate->context()->global_context()->closure();
8295 } else {
8296 function = JSFunction::cast(args[1]);
8297 }
8298
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008299 Context* context;
8300 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008301 isolate->heap()->AllocateWithContext(function,
8302 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008303 extension_object);
8304 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008305 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008306 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008307}
8308
8309
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008310RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008311 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008312 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008313 String* name = String::cast(args[0]);
8314 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008315 JSFunction* function;
8316 if (args[2]->IsSmi()) {
8317 // A smi sentinel indicates a context nested inside global code rather
8318 // than some function. There is a canonical empty function that can be
8319 // gotten from the global context.
8320 function = isolate->context()->global_context()->closure();
8321 } else {
8322 function = JSFunction::cast(args[2]);
8323 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008324 Context* context;
8325 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008326 isolate->heap()->AllocateCatchContext(function,
8327 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008328 name,
8329 thrown_object);
8330 if (!maybe_context->To(&context)) return maybe_context;
8331 isolate->set_context(context);
8332 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008333}
8334
8335
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008336RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8337 NoHandleAllocation ha;
8338 ASSERT(args.length() == 2);
8339 SerializedScopeInfo* scope_info = SerializedScopeInfo::cast(args[0]);
8340 JSFunction* function;
8341 if (args[1]->IsSmi()) {
8342 // A smi sentinel indicates a context nested inside global code rather
8343 // than some function. There is a canonical empty function that can be
8344 // gotten from the global context.
8345 function = isolate->context()->global_context()->closure();
8346 } else {
8347 function = JSFunction::cast(args[1]);
8348 }
8349 Context* context;
8350 MaybeObject* maybe_context =
8351 isolate->heap()->AllocateBlockContext(function,
8352 isolate->context(),
8353 scope_info);
8354 if (!maybe_context->To(&context)) return maybe_context;
8355 isolate->set_context(context);
8356 return context;
8357}
8358
8359
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008360RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008361 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008362 ASSERT(args.length() == 2);
8363
8364 CONVERT_ARG_CHECKED(Context, context, 0);
8365 CONVERT_ARG_CHECKED(String, name, 1);
8366
8367 int index;
8368 PropertyAttributes attributes;
8369 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008370 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008371
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008372 // If the slot was not found the result is true.
8373 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008374 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008375 }
8376
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008377 // If the slot was found in a context, it should be DONT_DELETE.
8378 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008379 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008380 }
8381
8382 // The slot was found in a JSObject, either a context extension object,
8383 // the global object, or an arguments object. Try to delete it
8384 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
8385 // which allows deleting all parameters in functions that mention
8386 // 'arguments', we do this even for the case of slots found on an
8387 // arguments object. The slot was found on an arguments object if the
8388 // index is non-negative.
8389 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8390 if (index >= 0) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008391 return object->DeleteElement(index, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008392 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008393 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008394 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008395}
8396
8397
ager@chromium.orga1645e22009-09-09 19:27:10 +00008398// A mechanism to return a pair of Object pointers in registers (if possible).
8399// How this is achieved is calling convention-dependent.
8400// All currently supported x86 compiles uses calling conventions that are cdecl
8401// variants where a 64-bit value is returned in two 32-bit registers
8402// (edx:eax on ia32, r1:r0 on ARM).
8403// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8404// In Win64 calling convention, a struct of two pointers is returned in memory,
8405// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008406#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008407struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008408 MaybeObject* x;
8409 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008410};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008411
lrn@chromium.org303ada72010-10-27 09:33:13 +00008412static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008413 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008414 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8415 // In Win64 they are assigned to a hidden first argument.
8416 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008417}
8418#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008419typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008420static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008421 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008422 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008423}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008424#endif
8425
8426
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008427static inline MaybeObject* Unhole(Heap* heap,
8428 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008429 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008430 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8431 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008432 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008433}
8434
8435
danno@chromium.org40cb8782011-05-25 07:58:50 +00008436static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8437 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008438 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008439 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008440 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008441 JSFunction* context_extension_function =
8442 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008443 // If the holder isn't a context extension object, we just return it
8444 // as the receiver. This allows arguments objects to be used as
8445 // receivers, but only if they are put in the context scope chain
8446 // explicitly via a with-statement.
8447 Object* constructor = holder->map()->constructor();
8448 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008449 // Fall back to using the global object as the implicit receiver if
8450 // the property turns out to be a local variable allocated in a
8451 // context extension object - introduced via eval. Implicit global
8452 // receivers are indicated with the hole value.
8453 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008454}
8455
8456
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008457static ObjectPair LoadContextSlotHelper(Arguments args,
8458 Isolate* isolate,
8459 bool throw_error) {
8460 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008461 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008462
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008463 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008464 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008465 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008466 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008467 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008468
8469 int index;
8470 PropertyAttributes attributes;
8471 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008472 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008473
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008474 // If the index is non-negative, the slot has been found in a local
8475 // variable or a parameter. Read it from the context object or the
8476 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008477 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008478 // If the "property" we were looking for is a local variable or an
8479 // argument in a context, the receiver is the global object; see
8480 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008481 //
8482 // Use the hole as the receiver to signal that the receiver is
8483 // implicit and that the global receiver should be used.
8484 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008485 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008486 ? Context::cast(*holder)->get(index)
8487 : JSObject::cast(*holder)->GetElement(index);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008488 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008489 }
8490
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008491 // If the holder is found, we read the property from it.
8492 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008493 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008494 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008495 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008496 if (object->IsGlobalObject()) {
8497 receiver = GlobalObject::cast(object)->global_receiver();
8498 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008499 // Use the hole as the receiver to signal that the receiver is
8500 // implicit and that the global receiver should be used.
8501 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008502 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008503 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008504 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008505
8506 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008507 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008508
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008509 // No need to unhole the value here. This is taken care of by the
8510 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008511 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008512 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008513 }
8514
8515 if (throw_error) {
8516 // The property doesn't exist - throw exception.
8517 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008518 isolate->factory()->NewReferenceError("not_defined",
8519 HandleVector(&name, 1));
8520 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008521 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008522 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008523 return MakePair(isolate->heap()->undefined_value(),
8524 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008525 }
8526}
8527
8528
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008529RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008530 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008531}
8532
8533
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008534RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008535 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008536}
8537
8538
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008539RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008540 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008541 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008542
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008543 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008544 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008545 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008546 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008547 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8548 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008549 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008550
8551 int index;
8552 PropertyAttributes attributes;
8553 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008554 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008555
8556 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008557 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008558 // Ignore if read_only variable.
8559 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008560 // Context is a fixed array and set cannot fail.
8561 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008562 } else if (strict_mode == kStrictMode) {
8563 // Setting read only property in strict mode.
8564 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008565 isolate->factory()->NewTypeError("strict_cannot_assign",
8566 HandleVector(&name, 1));
8567 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008568 }
8569 } else {
8570 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008571 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008572 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008573 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008574 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008575 return Failure::Exception();
8576 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008577 }
8578 return *value;
8579 }
8580
8581 // Slow case: The property is not in a FixedArray context.
8582 // It is either in an JSObject extension context or it was not found.
8583 Handle<JSObject> context_ext;
8584
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008585 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008586 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008587 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008588 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008589 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008590 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008591
8592 if (strict_mode == kStrictMode) {
8593 // Throw in strict mode (assignment to undefined variable).
8594 Handle<Object> error =
8595 isolate->factory()->NewReferenceError(
8596 "not_defined", HandleVector(&name, 1));
8597 return isolate->Throw(*error);
8598 }
8599 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008600 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008601 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008602 }
8603
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008604 // Set the property, but ignore if read_only variable on the context
8605 // extension object itself.
8606 if ((attributes & READ_ONLY) == 0 ||
8607 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008608 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008609 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008610 SetProperty(context_ext, name, value, NONE, strict_mode));
8611 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008612 // Setting read only property in strict mode.
8613 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008614 isolate->factory()->NewTypeError(
8615 "strict_cannot_assign", HandleVector(&name, 1));
8616 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008617 }
8618 return *value;
8619}
8620
8621
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008622RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008623 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008624 ASSERT(args.length() == 1);
8625
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008626 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008627}
8628
8629
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008630RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008631 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008632 ASSERT(args.length() == 1);
8633
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008634 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008635}
8636
8637
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008638RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008639 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008640 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008641}
8642
8643
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008644RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008645 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008646 ASSERT(args.length() == 1);
8647
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008648 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008649 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008650 isolate->factory()->NewReferenceError("not_defined",
8651 HandleVector(&name, 1));
8652 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008653}
8654
8655
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008656RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008657 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008658
8659 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008660 if (isolate->stack_guard()->IsStackOverflow()) {
8661 NoHandleAllocation na;
8662 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008663 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008664
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008665 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008666}
8667
8668
8669// NOTE: These PrintXXX functions are defined for all builds (not just
8670// DEBUG builds) because we may want to be able to trace function
8671// calls in all modes.
8672static void PrintString(String* str) {
8673 // not uncommon to have empty strings
8674 if (str->length() > 0) {
8675 SmartPointer<char> s =
8676 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8677 PrintF("%s", *s);
8678 }
8679}
8680
8681
8682static void PrintObject(Object* obj) {
8683 if (obj->IsSmi()) {
8684 PrintF("%d", Smi::cast(obj)->value());
8685 } else if (obj->IsString() || obj->IsSymbol()) {
8686 PrintString(String::cast(obj));
8687 } else if (obj->IsNumber()) {
8688 PrintF("%g", obj->Number());
8689 } else if (obj->IsFailure()) {
8690 PrintF("<failure>");
8691 } else if (obj->IsUndefined()) {
8692 PrintF("<undefined>");
8693 } else if (obj->IsNull()) {
8694 PrintF("<null>");
8695 } else if (obj->IsTrue()) {
8696 PrintF("<true>");
8697 } else if (obj->IsFalse()) {
8698 PrintF("<false>");
8699 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008700 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008701 }
8702}
8703
8704
8705static int StackSize() {
8706 int n = 0;
8707 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8708 return n;
8709}
8710
8711
8712static void PrintTransition(Object* result) {
8713 // indentation
8714 { const int nmax = 80;
8715 int n = StackSize();
8716 if (n <= nmax)
8717 PrintF("%4d:%*s", n, n, "");
8718 else
8719 PrintF("%4d:%*s", n, nmax, "...");
8720 }
8721
8722 if (result == NULL) {
8723 // constructor calls
8724 JavaScriptFrameIterator it;
8725 JavaScriptFrame* frame = it.frame();
8726 if (frame->IsConstructor()) PrintF("new ");
8727 // function name
8728 Object* fun = frame->function();
8729 if (fun->IsJSFunction()) {
8730 PrintObject(JSFunction::cast(fun)->shared()->name());
8731 } else {
8732 PrintObject(fun);
8733 }
8734 // function arguments
8735 // (we are intentionally only printing the actually
8736 // supplied parameters, not all parameters required)
8737 PrintF("(this=");
8738 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008739 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008740 for (int i = 0; i < length; i++) {
8741 PrintF(", ");
8742 PrintObject(frame->GetParameter(i));
8743 }
8744 PrintF(") {\n");
8745
8746 } else {
8747 // function result
8748 PrintF("} -> ");
8749 PrintObject(result);
8750 PrintF("\n");
8751 }
8752}
8753
8754
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008755RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008756 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008757 NoHandleAllocation ha;
8758 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008759 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008760}
8761
8762
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008763RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008764 NoHandleAllocation ha;
8765 PrintTransition(args[0]);
8766 return args[0]; // return TOS
8767}
8768
8769
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008770RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008771 NoHandleAllocation ha;
8772 ASSERT(args.length() == 1);
8773
8774#ifdef DEBUG
8775 if (args[0]->IsString()) {
8776 // If we have a string, assume it's a code "marker"
8777 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008778 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008779 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008780 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8781 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008782 } else {
8783 PrintF("DebugPrint: ");
8784 }
8785 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008786 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008787 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008788 HeapObject::cast(args[0])->map()->Print();
8789 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008790#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008791 // ShortPrint is available in release mode. Print is not.
8792 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008793#endif
8794 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008795 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008796
8797 return args[0]; // return TOS
8798}
8799
8800
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008801RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008802 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008803 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008804 isolate->PrintStack();
8805 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008806}
8807
8808
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008809RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008810 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008811 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008812
8813 // According to ECMA-262, section 15.9.1, page 117, the precision of
8814 // the number in a Date object representing a particular instant in
8815 // time is milliseconds. Therefore, we floor the result of getting
8816 // the OS time.
8817 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008818 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008819}
8820
8821
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008822RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008823 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008824 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008825
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008826 CONVERT_ARG_CHECKED(String, str, 0);
8827 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008828
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008829 CONVERT_ARG_CHECKED(JSArray, output, 1);
8830 RUNTIME_ASSERT(output->HasFastElements());
8831
8832 AssertNoAllocation no_allocation;
8833
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008834 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008835 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8836 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008837 String::FlatContent str_content = str->GetFlatContent();
8838 if (str_content.IsAscii()) {
8839 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008840 output_array,
8841 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008842 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008843 ASSERT(str_content.IsTwoByte());
8844 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008845 output_array,
8846 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008847 }
8848
8849 if (result) {
8850 return *output;
8851 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008852 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008853 }
8854}
8855
8856
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008857RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008858 NoHandleAllocation ha;
8859 ASSERT(args.length() == 1);
8860
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008861 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008862 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008863 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008864}
8865
8866
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008867RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008868 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008869 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008870
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008871 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008872}
8873
8874
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008875RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008876 NoHandleAllocation ha;
8877 ASSERT(args.length() == 1);
8878
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008879 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008880 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008881}
8882
8883
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008884RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008885 ASSERT(args.length() == 1);
8886 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008887 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008888 return JSGlobalObject::cast(global)->global_receiver();
8889}
8890
8891
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008892RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008893 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008894 ASSERT_EQ(1, args.length());
8895 CONVERT_ARG_CHECKED(String, source, 0);
8896
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008897 source = Handle<String>(source->TryFlattenGetString());
8898 // Optimized fast case where we only have ascii characters.
8899 Handle<Object> result;
8900 if (source->IsSeqAsciiString()) {
8901 result = JsonParser<true>::Parse(source);
8902 } else {
8903 result = JsonParser<false>::Parse(source);
8904 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008905 if (result.is_null()) {
8906 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008907 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008908 return Failure::Exception();
8909 }
8910 return *result;
8911}
8912
8913
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008914bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8915 Handle<Context> context) {
8916 if (context->allow_code_gen_from_strings()->IsFalse()) {
8917 // Check with callback if set.
8918 AllowCodeGenerationFromStringsCallback callback =
8919 isolate->allow_code_gen_callback();
8920 if (callback == NULL) {
8921 // No callback set and code generation disallowed.
8922 return false;
8923 } else {
8924 // Callback set. Let it decide if code generation is allowed.
8925 VMState state(isolate, EXTERNAL);
8926 return callback(v8::Utils::ToLocal(context));
8927 }
8928 }
8929 return true;
8930}
8931
8932
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008933RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008934 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008935 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008936 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008937
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008938 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008939 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008940
8941 // Check if global context allows code generation from
8942 // strings. Throw an exception if it doesn't.
8943 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8944 return isolate->Throw(*isolate->factory()->NewError(
8945 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8946 }
8947
8948 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008949 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8950 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008951 true,
8952 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008953 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008954 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008955 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8956 context,
8957 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008958 return *fun;
8959}
8960
8961
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008962static ObjectPair CompileGlobalEval(Isolate* isolate,
8963 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008964 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008965 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008966 Handle<Context> context = Handle<Context>(isolate->context());
8967 Handle<Context> global_context = Handle<Context>(context->global_context());
8968
8969 // Check if global context allows code generation from
8970 // strings. Throw an exception if it doesn't.
8971 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8972 isolate->Throw(*isolate->factory()->NewError(
8973 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8974 return MakePair(Failure::Exception(), NULL);
8975 }
8976
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008977 // Deal with a normal eval call with a string argument. Compile it
8978 // and return the compiled function bound in the local context.
8979 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8980 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008981 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008982 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008983 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008984 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008985 Handle<JSFunction> compiled =
8986 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008987 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008988 return MakePair(*compiled, *receiver);
8989}
8990
8991
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008992RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008993 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008994
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008995 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008996 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008997 Handle<Object> receiver; // Will be overwritten.
8998
8999 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009000 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009001#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009002 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009003 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009004 StackFrameLocator locator;
9005 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009006 ASSERT(Context::cast(frame->context()) == *context);
9007#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009008
9009 // Find where the 'eval' symbol is bound. It is unaliased only if
9010 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009011 int index = -1;
9012 PropertyAttributes attributes = ABSENT;
9013 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009014 receiver = context->Lookup(isolate->factory()->eval_symbol(),
9015 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009016 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009017 // Stop search when eval is found or when the global context is
9018 // reached.
9019 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009020 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009021 }
9022
iposva@chromium.org245aa852009-02-10 00:49:54 +00009023 // If eval could not be resolved, it has been deleted and we need to
9024 // throw a reference error.
9025 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009026 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00009027 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009028 isolate->factory()->NewReferenceError("not_defined",
9029 HandleVector(&name, 1));
9030 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009031 }
9032
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009033 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009034 // 'eval' is not bound in the global context. Just call the function
9035 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00009036 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009037 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009038 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009039 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009040 }
9041
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009042 // 'eval' is bound in the global context, but it may have been overwritten.
9043 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009044 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009045 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009046 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009047 }
9048
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009049 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009050 return CompileGlobalEval(isolate,
9051 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009052 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009053 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009054}
9055
9056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009057RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009058 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009059
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009060 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009061 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009062
9063 // 'eval' is bound in the global context, but it may have been overwritten.
9064 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009065 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009066 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009067 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009068 }
9069
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009070 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009071 return CompileGlobalEval(isolate,
9072 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009073 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009074 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009075}
9076
9077
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009078RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009079 // This utility adjusts the property attributes for newly created Function
9080 // object ("new Function(...)") by changing the map.
9081 // All it does is changing the prototype property to enumerable
9082 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009083 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009084 ASSERT(args.length() == 1);
9085 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009086
9087 Handle<Map> map = func->shared()->strict_mode()
9088 ? isolate->strict_mode_function_instance_map()
9089 : isolate->function_instance_map();
9090
9091 ASSERT(func->map()->instance_type() == map->instance_type());
9092 ASSERT(func->map()->instance_size() == map->instance_size());
9093 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009094 return *func;
9095}
9096
9097
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009098RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009099 // Allocate a block of memory in NewSpace (filled with a filler).
9100 // Use as fallback for allocation in generated code when NewSpace
9101 // is full.
9102 ASSERT(args.length() == 1);
9103 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9104 int size = size_smi->value();
9105 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9106 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009107 Heap* heap = isolate->heap();
9108 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009109 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009110 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009111 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009112 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009113 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009114 }
9115 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009116 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009117}
9118
9119
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009120// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009121// array. Returns true if the element was pushed on the stack and
9122// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009123RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009124 ASSERT(args.length() == 2);
9125 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009126 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009127 RUNTIME_ASSERT(array->HasFastElements());
9128 int length = Smi::cast(array->length())->value();
9129 FixedArray* elements = FixedArray::cast(array->elements());
9130 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009131 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009132 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009133 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009134 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009135 { MaybeObject* maybe_obj =
9136 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009137 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9138 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009139 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009140}
9141
9142
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009143/**
9144 * A simple visitor visits every element of Array's.
9145 * The backend storage can be a fixed array for fast elements case,
9146 * or a dictionary for sparse array. Since Dictionary is a subtype
9147 * of FixedArray, the class can be used by both fast and slow cases.
9148 * The second parameter of the constructor, fast_elements, specifies
9149 * whether the storage is a FixedArray or Dictionary.
9150 *
9151 * An index limit is used to deal with the situation that a result array
9152 * length overflows 32-bit non-negative integer.
9153 */
9154class ArrayConcatVisitor {
9155 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009156 ArrayConcatVisitor(Isolate* isolate,
9157 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009158 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009159 isolate_(isolate),
9160 storage_(Handle<FixedArray>::cast(
9161 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009162 index_offset_(0u),
9163 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009164
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009165 ~ArrayConcatVisitor() {
9166 clear_storage();
9167 }
9168
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009169 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009170 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009171 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009172
9173 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009174 if (index < static_cast<uint32_t>(storage_->length())) {
9175 storage_->set(index, *elm);
9176 return;
9177 }
9178 // Our initial estimate of length was foiled, possibly by
9179 // getters on the arrays increasing the length of later arrays
9180 // during iteration.
9181 // This shouldn't happen in anything but pathological cases.
9182 SetDictionaryMode(index);
9183 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009184 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009185 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009186 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009187 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009188 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009189 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009190 // Dictionary needed to grow.
9191 clear_storage();
9192 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009193 }
9194}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009195
9196 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009197 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9198 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009199 } else {
9200 index_offset_ += delta;
9201 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009202 }
9203
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009204 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009205 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009206 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009207 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009208 Handle<Map> map;
9209 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009210 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009211 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009212 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009213 }
9214 array->set_map(*map);
9215 array->set_length(*length);
9216 array->set_elements(*storage_);
9217 return array;
9218 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009219
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009220 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009221 // Convert storage to dictionary mode.
9222 void SetDictionaryMode(uint32_t index) {
9223 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009224 Handle<FixedArray> current_storage(*storage_);
9225 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009226 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009227 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9228 for (uint32_t i = 0; i < current_length; i++) {
9229 HandleScope loop_scope;
9230 Handle<Object> element(current_storage->get(i));
9231 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009232 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009233 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009234 if (!new_storage.is_identical_to(slow_storage)) {
9235 slow_storage = loop_scope.CloseAndEscape(new_storage);
9236 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009237 }
9238 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009239 clear_storage();
9240 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009241 fast_elements_ = false;
9242 }
9243
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009244 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009245 isolate_->global_handles()->Destroy(
9246 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009247 }
9248
9249 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009250 storage_ = Handle<FixedArray>::cast(
9251 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009252 }
9253
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009254 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009255 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009256 // Index after last seen index. Always less than or equal to
9257 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009258 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009259 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009260};
9261
9262
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009263static uint32_t EstimateElementCount(Handle<JSArray> array) {
9264 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9265 int element_count = 0;
9266 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009267 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009268 // Fast elements can't have lengths that are not representable by
9269 // a 32-bit signed integer.
9270 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9271 int fast_length = static_cast<int>(length);
9272 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9273 for (int i = 0; i < fast_length; i++) {
9274 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009275 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009276 break;
9277 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009278 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009279 Handle<NumberDictionary> dictionary(
9280 NumberDictionary::cast(array->elements()));
9281 int capacity = dictionary->Capacity();
9282 for (int i = 0; i < capacity; i++) {
9283 Handle<Object> key(dictionary->KeyAt(i));
9284 if (dictionary->IsKey(*key)) {
9285 element_count++;
9286 }
9287 }
9288 break;
9289 }
9290 default:
9291 // External arrays are always dense.
9292 return length;
9293 }
9294 // As an estimate, we assume that the prototype doesn't contain any
9295 // inherited elements.
9296 return element_count;
9297}
9298
9299
9300
9301template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009302static void IterateExternalArrayElements(Isolate* isolate,
9303 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009304 bool elements_are_ints,
9305 bool elements_are_guaranteed_smis,
9306 ArrayConcatVisitor* visitor) {
9307 Handle<ExternalArrayClass> array(
9308 ExternalArrayClass::cast(receiver->elements()));
9309 uint32_t len = static_cast<uint32_t>(array->length());
9310
9311 ASSERT(visitor != NULL);
9312 if (elements_are_ints) {
9313 if (elements_are_guaranteed_smis) {
9314 for (uint32_t j = 0; j < len; j++) {
9315 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009316 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009317 visitor->visit(j, e);
9318 }
9319 } else {
9320 for (uint32_t j = 0; j < len; j++) {
9321 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009322 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009323 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9324 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9325 visitor->visit(j, e);
9326 } else {
9327 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009328 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009329 visitor->visit(j, e);
9330 }
9331 }
9332 }
9333 } else {
9334 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009335 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009336 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009337 visitor->visit(j, e);
9338 }
9339 }
9340}
9341
9342
9343// Used for sorting indices in a List<uint32_t>.
9344static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9345 uint32_t a = *ap;
9346 uint32_t b = *bp;
9347 return (a == b) ? 0 : (a < b) ? -1 : 1;
9348}
9349
9350
9351static void CollectElementIndices(Handle<JSObject> object,
9352 uint32_t range,
9353 List<uint32_t>* indices) {
9354 JSObject::ElementsKind kind = object->GetElementsKind();
9355 switch (kind) {
9356 case JSObject::FAST_ELEMENTS: {
9357 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9358 uint32_t length = static_cast<uint32_t>(elements->length());
9359 if (range < length) length = range;
9360 for (uint32_t i = 0; i < length; i++) {
9361 if (!elements->get(i)->IsTheHole()) {
9362 indices->Add(i);
9363 }
9364 }
9365 break;
9366 }
9367 case JSObject::DICTIONARY_ELEMENTS: {
9368 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009369 uint32_t capacity = dict->Capacity();
9370 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009371 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009372 Handle<Object> k(dict->KeyAt(j));
9373 if (dict->IsKey(*k)) {
9374 ASSERT(k->IsNumber());
9375 uint32_t index = static_cast<uint32_t>(k->Number());
9376 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009377 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009378 }
9379 }
9380 }
9381 break;
9382 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009383 default: {
9384 int dense_elements_length;
9385 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009386 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009387 dense_elements_length =
9388 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009389 break;
9390 }
9391 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009392 dense_elements_length =
9393 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009394 break;
9395 }
9396 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009397 dense_elements_length =
9398 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009399 break;
9400 }
9401 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009402 dense_elements_length =
9403 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009404 break;
9405 }
9406 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009407 dense_elements_length =
9408 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009409 break;
9410 }
9411 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009412 dense_elements_length =
9413 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009414 break;
9415 }
9416 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009417 dense_elements_length =
9418 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009419 break;
9420 }
9421 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009422 dense_elements_length =
9423 ExternalFloatArray::cast(object->elements())->length();
9424 break;
9425 }
9426 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9427 dense_elements_length =
9428 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009429 break;
9430 }
9431 default:
9432 UNREACHABLE();
9433 dense_elements_length = 0;
9434 break;
9435 }
9436 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9437 if (range <= length) {
9438 length = range;
9439 // We will add all indices, so we might as well clear it first
9440 // and avoid duplicates.
9441 indices->Clear();
9442 }
9443 for (uint32_t i = 0; i < length; i++) {
9444 indices->Add(i);
9445 }
9446 if (length == range) return; // All indices accounted for already.
9447 break;
9448 }
9449 }
9450
9451 Handle<Object> prototype(object->GetPrototype());
9452 if (prototype->IsJSObject()) {
9453 // The prototype will usually have no inherited element indices,
9454 // but we have to check.
9455 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9456 }
9457}
9458
9459
9460/**
9461 * A helper function that visits elements of a JSArray in numerical
9462 * order.
9463 *
9464 * The visitor argument called for each existing element in the array
9465 * with the element index and the element's value.
9466 * Afterwards it increments the base-index of the visitor by the array
9467 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009468 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009469 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009470static bool IterateElements(Isolate* isolate,
9471 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009472 ArrayConcatVisitor* visitor) {
9473 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9474 switch (receiver->GetElementsKind()) {
9475 case JSObject::FAST_ELEMENTS: {
9476 // Run through the elements FixedArray and use HasElement and GetElement
9477 // to check the prototype for missing elements.
9478 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9479 int fast_length = static_cast<int>(length);
9480 ASSERT(fast_length <= elements->length());
9481 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009482 HandleScope loop_scope(isolate);
9483 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009484 if (!element_value->IsTheHole()) {
9485 visitor->visit(j, element_value);
9486 } else if (receiver->HasElement(j)) {
9487 // Call GetElement on receiver, not its prototype, or getters won't
9488 // have the correct receiver.
9489 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009490 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009491 visitor->visit(j, element_value);
9492 }
9493 }
9494 break;
9495 }
9496 case JSObject::DICTIONARY_ELEMENTS: {
9497 Handle<NumberDictionary> dict(receiver->element_dictionary());
9498 List<uint32_t> indices(dict->Capacity() / 2);
9499 // Collect all indices in the object and the prototypes less
9500 // than length. This might introduce duplicates in the indices list.
9501 CollectElementIndices(receiver, length, &indices);
9502 indices.Sort(&compareUInt32);
9503 int j = 0;
9504 int n = indices.length();
9505 while (j < n) {
9506 HandleScope loop_scope;
9507 uint32_t index = indices[j];
9508 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009509 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009510 visitor->visit(index, element);
9511 // Skip to next different index (i.e., omit duplicates).
9512 do {
9513 j++;
9514 } while (j < n && indices[j] == index);
9515 }
9516 break;
9517 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009518 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
9519 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9520 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009521 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009522 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009523 visitor->visit(j, e);
9524 }
9525 break;
9526 }
9527 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
9528 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009529 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009530 break;
9531 }
9532 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9533 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009534 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009535 break;
9536 }
9537 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
9538 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009539 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009540 break;
9541 }
9542 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9543 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009544 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009545 break;
9546 }
9547 case JSObject::EXTERNAL_INT_ELEMENTS: {
9548 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009549 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009550 break;
9551 }
9552 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9553 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009554 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009555 break;
9556 }
9557 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9558 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009559 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009560 break;
9561 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009562 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9563 IterateExternalArrayElements<ExternalDoubleArray, double>(
9564 isolate, receiver, false, false, visitor);
9565 break;
9566 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009567 default:
9568 UNREACHABLE();
9569 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009570 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009571 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009572 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009573}
9574
9575
9576/**
9577 * Array::concat implementation.
9578 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009579 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009580 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009581 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009582RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009583 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009584 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009585
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009586 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9587 int argument_count = static_cast<int>(arguments->length()->Number());
9588 RUNTIME_ASSERT(arguments->HasFastElements());
9589 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009590
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009591 // Pass 1: estimate the length and number of elements of the result.
9592 // The actual length can be larger if any of the arguments have getters
9593 // that mutate other arguments (but will otherwise be precise).
9594 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009595
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009596 uint32_t estimate_result_length = 0;
9597 uint32_t estimate_nof_elements = 0;
9598 {
9599 for (int i = 0; i < argument_count; i++) {
9600 HandleScope loop_scope;
9601 Handle<Object> obj(elements->get(i));
9602 uint32_t length_estimate;
9603 uint32_t element_estimate;
9604 if (obj->IsJSArray()) {
9605 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9606 length_estimate =
9607 static_cast<uint32_t>(array->length()->Number());
9608 element_estimate =
9609 EstimateElementCount(array);
9610 } else {
9611 length_estimate = 1;
9612 element_estimate = 1;
9613 }
9614 // Avoid overflows by capping at kMaxElementCount.
9615 if (JSObject::kMaxElementCount - estimate_result_length <
9616 length_estimate) {
9617 estimate_result_length = JSObject::kMaxElementCount;
9618 } else {
9619 estimate_result_length += length_estimate;
9620 }
9621 if (JSObject::kMaxElementCount - estimate_nof_elements <
9622 element_estimate) {
9623 estimate_nof_elements = JSObject::kMaxElementCount;
9624 } else {
9625 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009626 }
9627 }
9628 }
9629
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009630 // If estimated number of elements is more than half of length, a
9631 // fixed array (fast case) is more time and space-efficient than a
9632 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009633 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009634
9635 Handle<FixedArray> storage;
9636 if (fast_case) {
9637 // The backing storage array must have non-existing elements to
9638 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009639 storage = isolate->factory()->NewFixedArrayWithHoles(
9640 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009641 } else {
9642 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9643 uint32_t at_least_space_for = estimate_nof_elements +
9644 (estimate_nof_elements >> 2);
9645 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009646 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009647 }
9648
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009649 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009650
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009651 for (int i = 0; i < argument_count; i++) {
9652 Handle<Object> obj(elements->get(i));
9653 if (obj->IsJSArray()) {
9654 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009655 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009656 return Failure::Exception();
9657 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009658 } else {
9659 visitor.visit(0, obj);
9660 visitor.increase_index_offset(1);
9661 }
9662 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009663
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009664 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009665}
9666
9667
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009668// This will not allocate (flatten the string), but it may run
9669// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009670RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009671 NoHandleAllocation ha;
9672 ASSERT(args.length() == 1);
9673
9674 CONVERT_CHECKED(String, string, args[0]);
9675 StringInputBuffer buffer(string);
9676 while (buffer.has_more()) {
9677 uint16_t character = buffer.GetNext();
9678 PrintF("%c", character);
9679 }
9680 return string;
9681}
9682
ager@chromium.org5ec48922009-05-05 07:25:34 +00009683// Moves all own elements of an object, that are below a limit, to positions
9684// starting at zero. All undefined values are placed after non-undefined values,
9685// and are followed by non-existing element. Does not change the length
9686// property.
9687// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009688RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009689 ASSERT(args.length() == 2);
9690 CONVERT_CHECKED(JSObject, object, args[0]);
9691 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9692 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009693}
9694
9695
9696// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009697RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009698 ASSERT(args.length() == 2);
9699 CONVERT_CHECKED(JSArray, from, args[0]);
9700 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009701 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009702 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009703 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9704 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009705 maybe_new_map = to->map()->GetFastElementsMap();
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009706 } else if (new_elements->map() ==
9707 isolate->heap()->fixed_double_array_map()) {
9708 maybe_new_map = to->map()->GetFastDoubleElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009709 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009710 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009711 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009712 Object* new_map;
9713 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009714 to->set_map(Map::cast(new_map));
9715 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009716 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009717 Object* obj;
9718 { MaybeObject* maybe_obj = from->ResetElements();
9719 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9720 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009721 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009722 return to;
9723}
9724
9725
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009726// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009727RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009728 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009729 CONVERT_CHECKED(JSObject, object, args[0]);
9730 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009731 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009732 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009733 } else if (object->IsJSArray()) {
9734 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009735 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009736 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009737 }
9738}
9739
9740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009741RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009742 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009743
9744 ASSERT_EQ(3, args.length());
9745
ager@chromium.orgac091b72010-05-05 07:34:42 +00009746 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009747 Handle<Object> key1 = args.at<Object>(1);
9748 Handle<Object> key2 = args.at<Object>(2);
9749
9750 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009751 if (!key1->ToArrayIndex(&index1)
9752 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009753 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009754 }
9755
ager@chromium.orgac091b72010-05-05 07:34:42 +00009756 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9757 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009758 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009759 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009760 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009761
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009762 RETURN_IF_EMPTY_HANDLE(isolate,
9763 SetElement(jsobject, index1, tmp2, kStrictMode));
9764 RETURN_IF_EMPTY_HANDLE(isolate,
9765 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009766
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009767 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009768}
9769
9770
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009771// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009772// might have elements. Can either return keys (positive integers) or
9773// intervals (pair of a negative integer (-start-1) followed by a
9774// positive (length)) or undefined values.
9775// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009776RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009777 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009778 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009779 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009780 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009781 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009782 // Create an array and get all the keys into it, then remove all the
9783 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009784 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009785 int keys_length = keys->length();
9786 for (int i = 0; i < keys_length; i++) {
9787 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009788 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009789 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009790 // Zap invalid keys.
9791 keys->set_undefined(i);
9792 }
9793 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009794 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009795 } else {
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009796 ASSERT(array->HasFastElements() || array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009797 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009798 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009799 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009800 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009801 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009802 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009803 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009804 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009805 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009806 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009807 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009808 }
9809}
9810
9811
9812// DefineAccessor takes an optional final argument which is the
9813// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9814// to the way accessors are implemented, it is set for both the getter
9815// and setter on the first call to DefineAccessor and ignored on
9816// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009817RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009818 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9819 // Compute attributes.
9820 PropertyAttributes attributes = NONE;
9821 if (args.length() == 5) {
9822 CONVERT_CHECKED(Smi, attrs, args[4]);
9823 int value = attrs->value();
9824 // Only attribute bits should be set.
9825 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9826 attributes = static_cast<PropertyAttributes>(value);
9827 }
9828
9829 CONVERT_CHECKED(JSObject, obj, args[0]);
9830 CONVERT_CHECKED(String, name, args[1]);
9831 CONVERT_CHECKED(Smi, flag, args[2]);
9832 CONVERT_CHECKED(JSFunction, fun, args[3]);
9833 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9834}
9835
9836
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009837RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009838 ASSERT(args.length() == 3);
9839 CONVERT_CHECKED(JSObject, obj, args[0]);
9840 CONVERT_CHECKED(String, name, args[1]);
9841 CONVERT_CHECKED(Smi, flag, args[2]);
9842 return obj->LookupAccessor(name, flag->value() == 0);
9843}
9844
9845
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009846#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009847RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009848 ASSERT(args.length() == 0);
9849 return Execution::DebugBreakHelper();
9850}
9851
9852
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009853// Helper functions for wrapping and unwrapping stack frame ids.
9854static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009855 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009856 return Smi::FromInt(id >> 2);
9857}
9858
9859
9860static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9861 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9862}
9863
9864
9865// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009866// args[0]: debug event listener function to set or null or undefined for
9867// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009868// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009869RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009870 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009871 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9872 args[0]->IsUndefined() ||
9873 args[0]->IsNull());
9874 Handle<Object> callback = args.at<Object>(0);
9875 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009876 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009877
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009878 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009879}
9880
9881
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009882RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009883 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009884 isolate->stack_guard()->DebugBreak();
9885 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009886}
9887
9888
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009889static MaybeObject* DebugLookupResultValue(Heap* heap,
9890 Object* receiver,
9891 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009892 LookupResult* result,
9893 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009894 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009895 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009896 case NORMAL:
9897 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009898 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009899 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009900 }
9901 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009902 case FIELD:
9903 value =
9904 JSObject::cast(
9905 result->holder())->FastPropertyAt(result->GetFieldIndex());
9906 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009907 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009908 }
9909 return value;
9910 case CONSTANT_FUNCTION:
9911 return result->GetConstantFunction();
9912 case CALLBACKS: {
9913 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009914 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009915 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009916 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009917 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009918 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009919 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009920 maybe_value = heap->isolate()->pending_exception();
9921 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009922 if (caught_exception != NULL) {
9923 *caught_exception = true;
9924 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009925 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009926 }
9927 return value;
9928 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009929 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009930 }
9931 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009932 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009933 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009934 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009935 case CONSTANT_TRANSITION:
9936 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009937 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009938 default:
9939 UNREACHABLE();
9940 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009941 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009942 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009943}
9944
9945
ager@chromium.org32912102009-01-16 10:38:43 +00009946// Get debugger related details for an object property.
9947// args[0]: object holding property
9948// args[1]: name of the property
9949//
9950// The array returned contains the following information:
9951// 0: Property value
9952// 1: Property details
9953// 2: Property value is exception
9954// 3: Getter function if defined
9955// 4: Setter function if defined
9956// Items 2-4 are only filled if the property has either a getter or a setter
9957// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009958RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009959 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009960
9961 ASSERT(args.length() == 2);
9962
9963 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9964 CONVERT_ARG_CHECKED(String, name, 1);
9965
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009966 // Make sure to set the current context to the context before the debugger was
9967 // entered (if the debugger is entered). The reason for switching context here
9968 // is that for some property lookups (accessors and interceptors) callbacks
9969 // into the embedding application can occour, and the embedding application
9970 // could have the assumption that its own global context is the current
9971 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009972 SaveContext save(isolate);
9973 if (isolate->debug()->InDebugger()) {
9974 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009975 }
9976
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009977 // Skip the global proxy as it has no properties and always delegates to the
9978 // real global object.
9979 if (obj->IsJSGlobalProxy()) {
9980 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9981 }
9982
9983
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009984 // Check if the name is trivially convertible to an index and get the element
9985 // if so.
9986 uint32_t index;
9987 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009988 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009989 Object* element_or_char;
9990 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009991 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009992 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9993 return maybe_element_or_char;
9994 }
9995 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009996 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009997 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009998 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009999 }
10000
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010001 // Find the number of objects making up this.
10002 int length = LocalPrototypeChainLength(*obj);
10003
10004 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010005 Handle<JSObject> jsproto = obj;
10006 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010007 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010008 jsproto->LocalLookup(*name, &result);
10009 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010010 // LookupResult is not GC safe as it holds raw object pointers.
10011 // GC can happen later in this code so put the required fields into
10012 // local variables using handles when required for later use.
10013 PropertyType result_type = result.type();
10014 Handle<Object> result_callback_obj;
10015 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010016 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10017 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010018 }
10019 Smi* property_details = result.GetPropertyDetails().AsSmi();
10020 // DebugLookupResultValue can cause GC so details from LookupResult needs
10021 // to be copied to handles before this.
10022 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010023 Object* raw_value;
10024 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010025 DebugLookupResultValue(isolate->heap(), *obj, *name,
10026 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010027 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10028 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010029 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010030
10031 // If the callback object is a fixed array then it contains JavaScript
10032 // getter and/or setter.
10033 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
10034 result_callback_obj->IsFixedArray();
10035 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010036 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010037 details->set(0, *value);
10038 details->set(1, property_details);
10039 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010040 details->set(2, isolate->heap()->ToBoolean(caught_exception));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010041 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
10042 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
10043 }
10044
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010045 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010046 }
10047 if (i < length - 1) {
10048 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10049 }
10050 }
10051
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010052 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010053}
10054
10055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010056RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010057 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010058
10059 ASSERT(args.length() == 2);
10060
10061 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10062 CONVERT_ARG_CHECKED(String, name, 1);
10063
10064 LookupResult result;
10065 obj->Lookup(*name, &result);
10066 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010067 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010068 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010069 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010070}
10071
10072
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010073// Return the property type calculated from the property details.
10074// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010075RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010076 ASSERT(args.length() == 1);
10077 CONVERT_CHECKED(Smi, details, args[0]);
10078 PropertyType type = PropertyDetails(details).type();
10079 return Smi::FromInt(static_cast<int>(type));
10080}
10081
10082
10083// Return the property attribute calculated from the property details.
10084// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010085RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010086 ASSERT(args.length() == 1);
10087 CONVERT_CHECKED(Smi, details, args[0]);
10088 PropertyAttributes attributes = PropertyDetails(details).attributes();
10089 return Smi::FromInt(static_cast<int>(attributes));
10090}
10091
10092
10093// Return the property insertion index calculated from the property details.
10094// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010095RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010096 ASSERT(args.length() == 1);
10097 CONVERT_CHECKED(Smi, details, args[0]);
10098 int index = PropertyDetails(details).index();
10099 return Smi::FromInt(index);
10100}
10101
10102
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010103// Return property value from named interceptor.
10104// args[0]: object
10105// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010106RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010107 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010108 ASSERT(args.length() == 2);
10109 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10110 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10111 CONVERT_ARG_CHECKED(String, name, 1);
10112
10113 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010114 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010115}
10116
10117
10118// Return element value from indexed interceptor.
10119// args[0]: object
10120// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010121RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010122 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010123 ASSERT(args.length() == 2);
10124 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10125 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10126 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10127
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010128 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010129}
10130
10131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010132RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010133 ASSERT(args.length() >= 1);
10134 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010135 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010136 if (isolate->debug()->break_id() == 0 ||
10137 break_id != isolate->debug()->break_id()) {
10138 return isolate->Throw(
10139 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010140 }
10141
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010142 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010143}
10144
10145
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010146RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010147 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010148 ASSERT(args.length() == 1);
10149
10150 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010151 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010152 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10153 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010154 if (!maybe_result->ToObject(&result)) return maybe_result;
10155 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010156
10157 // Count all frames which are relevant to debugging stack trace.
10158 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010159 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010160 if (id == StackFrame::NO_ID) {
10161 // If there is no JavaScript stack frame count is 0.
10162 return Smi::FromInt(0);
10163 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010164
10165 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10166 n += it.frame()->GetInlineCount();
10167 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010168 return Smi::FromInt(n);
10169}
10170
10171
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010172class FrameInspector {
10173 public:
10174 FrameInspector(JavaScriptFrame* frame,
10175 int inlined_frame_index,
10176 Isolate* isolate)
10177 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10178 // Calculate the deoptimized frame.
10179 if (frame->is_optimized()) {
10180 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10181 frame, inlined_frame_index, isolate);
10182 }
10183 has_adapted_arguments_ = frame_->has_adapted_arguments();
10184 is_optimized_ = frame_->is_optimized();
10185 }
10186
10187 ~FrameInspector() {
10188 // Get rid of the calculated deoptimized frame if any.
10189 if (deoptimized_frame_ != NULL) {
10190 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10191 isolate_);
10192 }
10193 }
10194
10195 int GetParametersCount() {
10196 return is_optimized_
10197 ? deoptimized_frame_->parameters_count()
10198 : frame_->ComputeParametersCount();
10199 }
10200 int expression_count() { return deoptimized_frame_->expression_count(); }
10201 Object* GetFunction() {
10202 return is_optimized_
10203 ? deoptimized_frame_->GetFunction()
10204 : frame_->function();
10205 }
10206 Object* GetParameter(int index) {
10207 return is_optimized_
10208 ? deoptimized_frame_->GetParameter(index)
10209 : frame_->GetParameter(index);
10210 }
10211 Object* GetExpression(int index) {
10212 return is_optimized_
10213 ? deoptimized_frame_->GetExpression(index)
10214 : frame_->GetExpression(index);
10215 }
10216
10217 // To inspect all the provided arguments the frame might need to be
10218 // replaced with the arguments frame.
10219 void SetArgumentsFrame(JavaScriptFrame* frame) {
10220 ASSERT(has_adapted_arguments_);
10221 frame_ = frame;
10222 is_optimized_ = frame_->is_optimized();
10223 ASSERT(!is_optimized_);
10224 }
10225
10226 private:
10227 JavaScriptFrame* frame_;
10228 DeoptimizedFrameInfo* deoptimized_frame_;
10229 Isolate* isolate_;
10230 bool is_optimized_;
10231 bool has_adapted_arguments_;
10232
10233 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10234};
10235
10236
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010237static const int kFrameDetailsFrameIdIndex = 0;
10238static const int kFrameDetailsReceiverIndex = 1;
10239static const int kFrameDetailsFunctionIndex = 2;
10240static const int kFrameDetailsArgumentCountIndex = 3;
10241static const int kFrameDetailsLocalCountIndex = 4;
10242static const int kFrameDetailsSourcePositionIndex = 5;
10243static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010244static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010245static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010246static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010247
10248// Return an array with frame details
10249// args[0]: number: break id
10250// args[1]: number: frame index
10251//
10252// The array returned contains the following information:
10253// 0: Frame id
10254// 1: Receiver
10255// 2: Function
10256// 3: Argument count
10257// 4: Local count
10258// 5: Source position
10259// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010260// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010261// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010262// Arguments name, value
10263// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010264// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010265RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010266 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010267 ASSERT(args.length() == 2);
10268
10269 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010270 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010271 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10272 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010273 if (!maybe_check->ToObject(&check)) return maybe_check;
10274 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010275 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010276 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010277
10278 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010279 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010280 if (id == StackFrame::NO_ID) {
10281 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010282 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010283 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010284
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010285 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010286
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010287 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010288 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010289 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010290 if (index < count + it.frame()->GetInlineCount()) break;
10291 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010292 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010293 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010294
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010295 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010296 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010297 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010298 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010299 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010300
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010301 // Traverse the saved contexts chain to find the active context for the
10302 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010303 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010304 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010305 save = save->prev();
10306 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010307 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010308
10309 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010310 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010311
10312 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010313 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010314 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010315
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010316 // Check for constructor frame. Inlined frames cannot be construct calls.
10317 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010318 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010319 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010320
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010321 // Get scope info and read from it for local variable information.
10322 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010323 Handle<SharedFunctionInfo> shared(function->shared());
10324 Handle<SerializedScopeInfo> scope_info(shared->scope_info());
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010325 ASSERT(*scope_info != SerializedScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010326 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010327
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010328 // Get the locals names and values into a temporary array.
10329 //
10330 // TODO(1240907): Hide compiler-introduced stack variables
10331 // (e.g. .result)? For users of the debugger, they will probably be
10332 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010333 Handle<FixedArray> locals =
10334 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010335
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010336 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010337 int i = 0;
10338 for (; i < info.number_of_stack_slots(); ++i) {
10339 // Use the value from the stack.
10340 locals->set(i * 2, *info.LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010341 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010342 }
10343 if (i < info.NumberOfLocals()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010344 // Get the context containing declarations.
10345 Handle<Context> context(
10346 Context::cast(it.frame()->context())->declaration_context());
10347 for (; i < info.NumberOfLocals(); ++i) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010348 Handle<String> name = info.LocalName(i);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010349 locals->set(i * 2, *name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010350 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010351 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010352 }
10353 }
10354
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010355 // Check whether this frame is positioned at return. If not top
10356 // frame or if the frame is optimized it cannot be at a return.
10357 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010358 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010359 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010360 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010361
10362 // If positioned just before return find the value to be returned and add it
10363 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010364 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010365 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010366 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010367 Address internal_frame_sp = NULL;
10368 while (!it2.done()) {
10369 if (it2.frame()->is_internal()) {
10370 internal_frame_sp = it2.frame()->sp();
10371 } else {
10372 if (it2.frame()->is_java_script()) {
10373 if (it2.frame()->id() == it.frame()->id()) {
10374 // The internal frame just before the JavaScript frame contains the
10375 // value to return on top. A debug break at return will create an
10376 // internal frame to store the return value (eax/rax/r0) before
10377 // entering the debug break exit frame.
10378 if (internal_frame_sp != NULL) {
10379 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010380 Handle<Object>(Memory::Object_at(internal_frame_sp),
10381 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010382 break;
10383 }
10384 }
10385 }
10386
10387 // Indicate that the previous frame was not an internal frame.
10388 internal_frame_sp = NULL;
10389 }
10390 it2.Advance();
10391 }
10392 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010393
10394 // Now advance to the arguments adapter frame (if any). It contains all
10395 // the provided parameters whereas the function frame always have the number
10396 // of arguments matching the functions parameters. The rest of the
10397 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010398 if (it.frame()->has_adapted_arguments()) {
10399 it.AdvanceToArgumentsFrame();
10400 frame_inspector.SetArgumentsFrame(it.frame());
10401 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010402
10403 // Find the number of arguments to fill. At least fill the number of
10404 // parameters for the function and fill more if more parameters are provided.
10405 int argument_count = info.number_of_parameters();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010406 if (argument_count < frame_inspector.GetParametersCount()) {
10407 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010408 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010409#ifdef DEBUG
10410 if (it.frame()->is_optimized()) {
10411 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10412 }
10413#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010414
10415 // Calculate the size of the result.
10416 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010417 2 * (argument_count + info.NumberOfLocals()) +
10418 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010419 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010420
10421 // Add the frame id.
10422 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10423
10424 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010425 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010426
10427 // Add the arguments count.
10428 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10429
10430 // Add the locals count
10431 details->set(kFrameDetailsLocalCountIndex,
10432 Smi::FromInt(info.NumberOfLocals()));
10433
10434 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010435 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010436 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10437 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010438 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010439 }
10440
10441 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010442 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010443
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010444 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010445 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010446
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010447 // Add flags to indicate information on whether this frame is
10448 // bit 0: invoked in the debugger context.
10449 // bit 1: optimized frame.
10450 // bit 2: inlined in optimized frame
10451 int flags = 0;
10452 if (*save->context() == *isolate->debug()->debug_context()) {
10453 flags |= 1 << 0;
10454 }
10455 if (it.frame()->is_optimized()) {
10456 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010457 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010458 }
10459 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010460
10461 // Fill the dynamic part.
10462 int details_index = kFrameDetailsFirstDynamicIndex;
10463
10464 // Add arguments name and value.
10465 for (int i = 0; i < argument_count; i++) {
10466 // Name of the argument.
10467 if (i < info.number_of_parameters()) {
10468 details->set(details_index++, *info.parameter_name(i));
10469 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010470 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010471 }
10472
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010473 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010474 if (i < it.frame()->ComputeParametersCount()) {
10475 // Get the value from the stack.
10476 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010477 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010478 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010479 }
10480 }
10481
10482 // Add locals name and value from the temporary copy from the function frame.
10483 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10484 details->set(details_index++, locals->get(i));
10485 }
10486
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010487 // Add the value being returned.
10488 if (at_return) {
10489 details->set(details_index++, *return_value);
10490 }
10491
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010492 // Add the receiver (same as in function frame).
10493 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10494 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010495 Handle<Object> receiver(it.frame()->receiver(), isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010496 if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
10497 // If the receiver is not a JSObject and the function is not a
10498 // builtin or strict-mode we have hit an optimization where a
10499 // value object is not converted into a wrapped JS objects. To
10500 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010501 // by creating correct wrapper object based on the calling frame's
10502 // global context.
10503 it.Advance();
10504 Handle<Context> calling_frames_global_context(
10505 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010506 receiver =
10507 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010508 }
10509 details->set(kFrameDetailsReceiverIndex, *receiver);
10510
10511 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010512 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010513}
10514
10515
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010516// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010517static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010518 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010519 Handle<SerializedScopeInfo> serialized_scope_info,
10520 ScopeInfo<>& scope_info,
10521 Handle<Context> context,
10522 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010523 // Fill all context locals to the context extension.
10524 for (int i = Context::MIN_CONTEXT_SLOTS;
10525 i < scope_info.number_of_context_slots();
10526 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010527 int context_index = serialized_scope_info->ContextSlotIndex(
10528 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010529
whesse@chromium.org7b260152011-06-20 15:33:18 +000010530 RETURN_IF_EMPTY_HANDLE_VALUE(
10531 isolate,
10532 SetProperty(scope_object,
10533 scope_info.context_slot_name(i),
10534 Handle<Object>(context->get(context_index), isolate),
10535 NONE,
10536 kNonStrictMode),
10537 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010538 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010539
10540 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010541}
10542
10543
10544// Create a plain JSObject which materializes the local scope for the specified
10545// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010546static Handle<JSObject> MaterializeLocalScope(
10547 Isolate* isolate,
10548 JavaScriptFrame* frame,
10549 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010550 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010551 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010552 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10553 ScopeInfo<> scope_info(*serialized_scope_info);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010554 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010555
10556 // Allocate and initialize a JSObject with all the arguments, stack locals
10557 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010558 Handle<JSObject> local_scope =
10559 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010560
10561 // First fill all parameters.
10562 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010563 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010564 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010565 SetProperty(local_scope,
10566 scope_info.parameter_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010567 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010568 NONE,
10569 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010570 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010571 }
10572
10573 // Second fill all stack locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010574 for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010575 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010576 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010577 SetProperty(local_scope,
10578 scope_info.stack_slot_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010579 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010580 NONE,
10581 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010582 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010583 }
10584
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010585 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10586 // Third fill all context locals.
10587 Handle<Context> frame_context(Context::cast(frame->context()));
10588 Handle<Context> function_context(frame_context->declaration_context());
10589 if (!CopyContextLocalsToScopeObject(isolate,
10590 serialized_scope_info, scope_info,
10591 function_context, local_scope)) {
10592 return Handle<JSObject>();
10593 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010594
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010595 // Finally copy any properties from the function context extension.
10596 // These will be variables introduced by eval.
10597 if (function_context->closure() == *function) {
10598 if (function_context->has_extension() &&
10599 !function_context->IsGlobalContext()) {
10600 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
10601 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
10602 for (int i = 0; i < keys->length(); i++) {
10603 // Names of variables introduced by eval are strings.
10604 ASSERT(keys->get(i)->IsString());
10605 Handle<String> key(String::cast(keys->get(i)));
10606 RETURN_IF_EMPTY_HANDLE_VALUE(
10607 isolate,
10608 SetProperty(local_scope,
10609 key,
10610 GetProperty(ext, key),
10611 NONE,
10612 kNonStrictMode),
10613 Handle<JSObject>());
10614 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010615 }
10616 }
10617 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010618
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010619 return local_scope;
10620}
10621
10622
10623// Create a plain JSObject which materializes the closure content for the
10624// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010625static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10626 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010627 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010628
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010629 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010630 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10631 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010632
10633 // Allocate and initialize a JSObject with all the content of theis function
10634 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010635 Handle<JSObject> closure_scope =
10636 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010637
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010638 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010639 if (!CopyContextLocalsToScopeObject(isolate,
10640 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010641 context, closure_scope)) {
10642 return Handle<JSObject>();
10643 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010644
10645 // Finally copy any properties from the function context extension. This will
10646 // be variables introduced by eval.
10647 if (context->has_extension()) {
10648 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010649 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010650 for (int i = 0; i < keys->length(); i++) {
10651 // Names of variables introduced by eval are strings.
10652 ASSERT(keys->get(i)->IsString());
10653 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010654 RETURN_IF_EMPTY_HANDLE_VALUE(
10655 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010656 SetProperty(closure_scope,
10657 key,
10658 GetProperty(ext, key),
10659 NONE,
10660 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010661 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010662 }
10663 }
10664
10665 return closure_scope;
10666}
10667
10668
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010669// Create a plain JSObject which materializes the scope for the specified
10670// catch context.
10671static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10672 Handle<Context> context) {
10673 ASSERT(context->IsCatchContext());
10674 Handle<String> name(String::cast(context->extension()));
10675 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10676 Handle<JSObject> catch_scope =
10677 isolate->factory()->NewJSObject(isolate->object_function());
10678 RETURN_IF_EMPTY_HANDLE_VALUE(
10679 isolate,
10680 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10681 Handle<JSObject>());
10682 return catch_scope;
10683}
10684
10685
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010686// Create a plain JSObject which materializes the block scope for the specified
10687// block context.
10688static Handle<JSObject> MaterializeBlockScope(
10689 Isolate* isolate,
10690 Handle<Context> context) {
10691 ASSERT(context->IsBlockContext());
10692 Handle<SerializedScopeInfo> serialized_scope_info(
10693 SerializedScopeInfo::cast(context->extension()));
10694 ScopeInfo<> scope_info(*serialized_scope_info);
10695
10696 // Allocate and initialize a JSObject with all the arguments, stack locals
10697 // heap locals and extension properties of the debugged function.
10698 Handle<JSObject> block_scope =
10699 isolate->factory()->NewJSObject(isolate->object_function());
10700
10701 // Fill all context locals.
10702 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10703 if (!CopyContextLocalsToScopeObject(isolate,
10704 serialized_scope_info, scope_info,
10705 context, block_scope)) {
10706 return Handle<JSObject>();
10707 }
10708 }
10709
10710 return block_scope;
10711}
10712
10713
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010714// Iterate over the actual scopes visible from a stack frame. All scopes are
10715// backed by an actual context except the local scope, which is inserted
10716// "artifically" in the context chain.
10717class ScopeIterator {
10718 public:
10719 enum ScopeType {
10720 ScopeTypeGlobal = 0,
10721 ScopeTypeLocal,
10722 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010723 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010724 ScopeTypeCatch,
10725 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010726 };
10727
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010728 ScopeIterator(Isolate* isolate,
10729 JavaScriptFrame* frame,
10730 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010731 : isolate_(isolate),
10732 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010733 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010734 function_(JSFunction::cast(frame->function())),
10735 context_(Context::cast(frame->context())),
10736 local_done_(false),
10737 at_local_(false) {
10738
10739 // Check whether the first scope is actually a local scope.
10740 if (context_->IsGlobalContext()) {
10741 // If there is a stack slot for .result then this local scope has been
10742 // created for evaluating top level code and it is not a real local scope.
10743 // Checking for the existence of .result seems fragile, but the scope info
10744 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010745 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010746 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010747 at_local_ = index < 0;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010748 } else if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010749 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010750 } else if (context_->closure() != *function_) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010751 // The context_ is a block or with or catch block from the outer function.
10752 ASSERT(context_->IsWithContext() ||
10753 context_->IsCatchContext() ||
10754 context_->IsBlockContext());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010755 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010756 }
10757 }
10758
10759 // More scopes?
10760 bool Done() { return context_.is_null(); }
10761
10762 // Move to the next scope.
10763 void Next() {
10764 // If at a local scope mark the local scope as passed.
10765 if (at_local_) {
10766 at_local_ = false;
10767 local_done_ = true;
10768
10769 // If the current context is not associated with the local scope the
10770 // current context is the next real scope, so don't move to the next
10771 // context in this case.
10772 if (context_->closure() != *function_) {
10773 return;
10774 }
10775 }
10776
10777 // The global scope is always the last in the chain.
10778 if (context_->IsGlobalContext()) {
10779 context_ = Handle<Context>();
10780 return;
10781 }
10782
10783 // Move to the next context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010784 context_ = Handle<Context>(context_->previous(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010785
10786 // If passing the local scope indicate that the current scope is now the
10787 // local scope.
10788 if (!local_done_ &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010789 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010790 at_local_ = true;
10791 }
10792 }
10793
10794 // Return the type of the current scope.
10795 int Type() {
10796 if (at_local_) {
10797 return ScopeTypeLocal;
10798 }
10799 if (context_->IsGlobalContext()) {
10800 ASSERT(context_->global()->IsGlobalObject());
10801 return ScopeTypeGlobal;
10802 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010803 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010804 return ScopeTypeClosure;
10805 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010806 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010807 return ScopeTypeCatch;
10808 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010809 if (context_->IsBlockContext()) {
10810 return ScopeTypeBlock;
10811 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010812 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010813 return ScopeTypeWith;
10814 }
10815
10816 // Return the JavaScript object with the content of the current scope.
10817 Handle<JSObject> ScopeObject() {
10818 switch (Type()) {
10819 case ScopeIterator::ScopeTypeGlobal:
10820 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010821 case ScopeIterator::ScopeTypeLocal:
10822 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010823 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010824 case ScopeIterator::ScopeTypeWith:
10825 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010826 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
10827 case ScopeIterator::ScopeTypeCatch:
10828 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010829 case ScopeIterator::ScopeTypeClosure:
10830 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010831 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010832 case ScopeIterator::ScopeTypeBlock:
10833 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010834 }
10835 UNREACHABLE();
10836 return Handle<JSObject>();
10837 }
10838
10839 // Return the context for this scope. For the local context there might not
10840 // be an actual context.
10841 Handle<Context> CurrentContext() {
10842 if (at_local_ && context_->closure() != *function_) {
10843 return Handle<Context>();
10844 }
10845 return context_;
10846 }
10847
10848#ifdef DEBUG
10849 // Debug print of the content of the current scope.
10850 void DebugPrint() {
10851 switch (Type()) {
10852 case ScopeIterator::ScopeTypeGlobal:
10853 PrintF("Global:\n");
10854 CurrentContext()->Print();
10855 break;
10856
10857 case ScopeIterator::ScopeTypeLocal: {
10858 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010859 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010860 scope_info.Print();
10861 if (!CurrentContext().is_null()) {
10862 CurrentContext()->Print();
10863 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010864 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010865 if (extension->IsJSContextExtensionObject()) {
10866 extension->Print();
10867 }
10868 }
10869 }
10870 break;
10871 }
10872
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010873 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010874 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010875 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010876 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010877
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010878 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010879 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010880 CurrentContext()->extension()->Print();
10881 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010882 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010883
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010884 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010885 PrintF("Closure:\n");
10886 CurrentContext()->Print();
10887 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010888 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010889 if (extension->IsJSContextExtensionObject()) {
10890 extension->Print();
10891 }
10892 }
10893 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010894
10895 default:
10896 UNREACHABLE();
10897 }
10898 PrintF("\n");
10899 }
10900#endif
10901
10902 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010903 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010904 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010905 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010906 Handle<JSFunction> function_;
10907 Handle<Context> context_;
10908 bool local_done_;
10909 bool at_local_;
10910
10911 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10912};
10913
10914
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010915RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010916 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010917 ASSERT(args.length() == 2);
10918
10919 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010920 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010921 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10922 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010923 if (!maybe_check->ToObject(&check)) return maybe_check;
10924 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010925 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10926
10927 // Get the frame where the debugging is performed.
10928 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010929 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010930 JavaScriptFrame* frame = it.frame();
10931
10932 // Count the visible scopes.
10933 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010934 for (ScopeIterator it(isolate, frame, 0);
10935 !it.Done();
10936 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010937 n++;
10938 }
10939
10940 return Smi::FromInt(n);
10941}
10942
10943
10944static const int kScopeDetailsTypeIndex = 0;
10945static const int kScopeDetailsObjectIndex = 1;
10946static const int kScopeDetailsSize = 2;
10947
10948// Return an array with scope details
10949// args[0]: number: break id
10950// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010951// args[2]: number: inlined frame index
10952// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010953//
10954// The array returned contains the following information:
10955// 0: Scope type
10956// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010957RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010958 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010959 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010960
10961 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010962 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010963 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10964 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010965 if (!maybe_check->ToObject(&check)) return maybe_check;
10966 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010967 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010968 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
10969 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010970
10971 // Get the frame where the debugging is performed.
10972 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010973 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010974 JavaScriptFrame* frame = frame_it.frame();
10975
10976 // Find the requested scope.
10977 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010978 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010979 for (; !it.Done() && n < index; it.Next()) {
10980 n++;
10981 }
10982 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010983 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010984 }
10985
10986 // Calculate the size of the result.
10987 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010988 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010989
10990 // Fill in scope details.
10991 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010992 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010993 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010994 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010995
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010996 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010997}
10998
10999
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011000RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011001 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011002 ASSERT(args.length() == 0);
11003
11004#ifdef DEBUG
11005 // Print the scopes for the top frame.
11006 StackFrameLocator locator;
11007 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011008 for (ScopeIterator it(isolate, frame, 0);
11009 !it.Done();
11010 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011011 it.DebugPrint();
11012 }
11013#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011014 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011015}
11016
11017
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011018RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011019 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011020 ASSERT(args.length() == 1);
11021
11022 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011023 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011024 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11025 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011026 if (!maybe_result->ToObject(&result)) return maybe_result;
11027 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011028
11029 // Count all archived V8 threads.
11030 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011031 for (ThreadState* thread =
11032 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011033 thread != NULL;
11034 thread = thread->Next()) {
11035 n++;
11036 }
11037
11038 // Total number of threads is current thread and archived threads.
11039 return Smi::FromInt(n + 1);
11040}
11041
11042
11043static const int kThreadDetailsCurrentThreadIndex = 0;
11044static const int kThreadDetailsThreadIdIndex = 1;
11045static const int kThreadDetailsSize = 2;
11046
11047// Return an array with thread details
11048// args[0]: number: break id
11049// args[1]: number: thread index
11050//
11051// The array returned contains the following information:
11052// 0: Is current thread?
11053// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011054RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011055 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011056 ASSERT(args.length() == 2);
11057
11058 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011059 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011060 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11061 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011062 if (!maybe_check->ToObject(&check)) return maybe_check;
11063 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011064 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11065
11066 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011067 Handle<FixedArray> details =
11068 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011069
11070 // Thread index 0 is current thread.
11071 if (index == 0) {
11072 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011073 details->set(kThreadDetailsCurrentThreadIndex,
11074 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011075 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011076 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011077 } else {
11078 // Find the thread with the requested index.
11079 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011080 ThreadState* thread =
11081 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011082 while (index != n && thread != NULL) {
11083 thread = thread->Next();
11084 n++;
11085 }
11086 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011087 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011088 }
11089
11090 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011091 details->set(kThreadDetailsCurrentThreadIndex,
11092 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011093 details->set(kThreadDetailsThreadIdIndex,
11094 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011095 }
11096
11097 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011098 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011099}
11100
11101
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011102// Sets the disable break state
11103// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011104RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011105 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011106 ASSERT(args.length() == 1);
11107 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011108 isolate->debug()->set_disable_break(disable_break);
11109 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011110}
11111
11112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011113RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011114 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011115 ASSERT(args.length() == 1);
11116
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011117 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11118 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011119 // Find the number of break points
11120 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011121 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011122 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011123 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011124 Handle<FixedArray>::cast(break_locations));
11125}
11126
11127
11128// Set a break point in a function
11129// args[0]: function
11130// args[1]: number: break source position (within the function source)
11131// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011132RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011133 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011134 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011135 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11136 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011137 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11138 RUNTIME_ASSERT(source_position >= 0);
11139 Handle<Object> break_point_object_arg = args.at<Object>(2);
11140
11141 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011142 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11143 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011144
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011145 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011146}
11147
11148
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011149Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11150 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011151 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011152 // Iterate the heap looking for SharedFunctionInfo generated from the
11153 // script. The inner most SharedFunctionInfo containing the source position
11154 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011155 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011156 // which is found is not compiled it is compiled and the heap is iterated
11157 // again as the compilation might create inner functions from the newly
11158 // compiled function and the actual requested break point might be in one of
11159 // these functions.
11160 bool done = false;
11161 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011162 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011163 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011164 while (!done) {
11165 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011166 for (HeapObject* obj = iterator.next();
11167 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011168 if (obj->IsSharedFunctionInfo()) {
11169 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11170 if (shared->script() == *script) {
11171 // If the SharedFunctionInfo found has the requested script data and
11172 // contains the source position it is a candidate.
11173 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000011174 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011175 start_position = shared->start_position();
11176 }
11177 if (start_position <= position &&
11178 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000011179 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011180 // candidate this is the new candidate.
11181 if (target.is_null()) {
11182 target_start_position = start_position;
11183 target = shared;
11184 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011185 if (target_start_position == start_position &&
11186 shared->end_position() == target->end_position()) {
11187 // If a top-level function contain only one function
11188 // declartion the source for the top-level and the function is
11189 // the same. In that case prefer the non top-level function.
11190 if (!shared->is_toplevel()) {
11191 target_start_position = start_position;
11192 target = shared;
11193 }
11194 } else if (target_start_position <= start_position &&
11195 shared->end_position() <= target->end_position()) {
11196 // This containment check includes equality as a function inside
11197 // a top-level function can share either start or end position
11198 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011199 target_start_position = start_position;
11200 target = shared;
11201 }
11202 }
11203 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011204 }
11205 }
11206 }
11207
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011208 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011209 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011210 }
11211
11212 // If the candidate found is compiled we are done. NOTE: when lazy
11213 // compilation of inner functions is introduced some additional checking
11214 // needs to be done here to compile inner functions.
11215 done = target->is_compiled();
11216 if (!done) {
11217 // If the candidate is not compiled compile it to reveal any inner
11218 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011219 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011220 }
11221 }
11222
11223 return *target;
11224}
11225
11226
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011227// Changes the state of a break point in a script and returns source position
11228// where break point was set. NOTE: Regarding performance see the NOTE for
11229// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011230// args[0]: script to set break point in
11231// args[1]: number: break source position (within the script source)
11232// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011233RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011234 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011235 ASSERT(args.length() == 3);
11236 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11237 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11238 RUNTIME_ASSERT(source_position >= 0);
11239 Handle<Object> break_point_object_arg = args.at<Object>(2);
11240
11241 // Get the script from the script wrapper.
11242 RUNTIME_ASSERT(wrapper->value()->IsScript());
11243 Handle<Script> script(Script::cast(wrapper->value()));
11244
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011245 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011246 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011247 if (!result->IsUndefined()) {
11248 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11249 // Find position within function. The script position might be before the
11250 // source position of the first function.
11251 int position;
11252 if (shared->start_position() > source_position) {
11253 position = 0;
11254 } else {
11255 position = source_position - shared->start_position();
11256 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011257 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011258 position += shared->start_position();
11259 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011260 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011261 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011262}
11263
11264
11265// Clear a break point
11266// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011267RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011268 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011269 ASSERT(args.length() == 1);
11270 Handle<Object> break_point_object_arg = args.at<Object>(0);
11271
11272 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011273 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011274
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011275 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011276}
11277
11278
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011279// Change the state of break on exceptions.
11280// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11281// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011282RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011283 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011284 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011285 RUNTIME_ASSERT(args[0]->IsNumber());
11286 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011287
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011288 // If the number doesn't match an enum value, the ChangeBreakOnException
11289 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011290 ExceptionBreakType type =
11291 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011292 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011293 isolate->debug()->ChangeBreakOnException(type, enable);
11294 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011295}
11296
11297
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011298// Returns the state of break on exceptions
11299// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011300RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011301 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011302 ASSERT(args.length() == 1);
11303 RUNTIME_ASSERT(args[0]->IsNumber());
11304
11305 ExceptionBreakType type =
11306 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011307 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011308 return Smi::FromInt(result);
11309}
11310
11311
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011312// Prepare for stepping
11313// args[0]: break id for checking execution state
11314// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011315// args[2]: number of times to perform the step, for step out it is the number
11316// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011317RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011318 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011319 ASSERT(args.length() == 3);
11320 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011321 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011322 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11323 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011324 if (!maybe_check->ToObject(&check)) return maybe_check;
11325 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011326 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011327 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011328 }
11329
11330 // Get the step action and check validity.
11331 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11332 if (step_action != StepIn &&
11333 step_action != StepNext &&
11334 step_action != StepOut &&
11335 step_action != StepInMin &&
11336 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011337 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011338 }
11339
11340 // Get the number of steps.
11341 int step_count = NumberToInt32(args[2]);
11342 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011343 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011344 }
11345
ager@chromium.orga1645e22009-09-09 19:27:10 +000011346 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011347 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011348
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011349 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011350 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11351 step_count);
11352 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011353}
11354
11355
11356// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011357RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011358 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011359 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011360 isolate->debug()->ClearStepping();
11361 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011362}
11363
11364
11365// Creates a copy of the with context chain. The copy of the context chain is
11366// is linked to the function context supplied.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011367static Handle<Context> CopyWithContextChain(Isolate* isolate,
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011368 Handle<JSFunction> function,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011369 Handle<Context> current,
11370 Handle<Context> base) {
11371 // At the end of the chain. Return the base context to link to.
11372 if (current->IsFunctionContext() || current->IsGlobalContext()) {
11373 return base;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011374 }
11375
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011376 // Recursively copy the with and catch contexts.
11377 HandleScope scope(isolate);
11378 Handle<Context> previous(current->previous());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011379 Handle<Context> new_previous =
11380 CopyWithContextChain(isolate, function, previous, base);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011381 Handle<Context> new_current;
11382 if (current->IsCatchContext()) {
11383 Handle<String> name(String::cast(current->extension()));
11384 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11385 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011386 isolate->factory()->NewCatchContext(function,
11387 new_previous,
11388 name,
11389 thrown_object);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011390 } else if (current->IsBlockContext()) {
11391 Handle<SerializedScopeInfo> scope_info(
11392 SerializedScopeInfo::cast(current->extension()));
11393 new_current =
11394 isolate->factory()->NewBlockContext(function, new_previous, scope_info);
danno@chromium.orgb6451162011-08-17 14:33:23 +000011395 // Copy context slots.
11396 int num_context_slots = scope_info->NumberOfContextSlots();
11397 for (int i = Context::MIN_CONTEXT_SLOTS; i < num_context_slots; ++i) {
11398 new_current->set(i, current->get(i));
11399 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011400 } else {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011401 ASSERT(current->IsWithContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011402 Handle<JSObject> extension(JSObject::cast(current->extension()));
11403 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011404 isolate->factory()->NewWithContext(function, new_previous, extension);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011405 }
11406 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011407}
11408
11409
11410// Helper function to find or create the arguments object for
11411// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011412static Handle<Object> GetArgumentsObject(Isolate* isolate,
11413 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011414 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011415 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011416 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011417 const ScopeInfo<>* sinfo,
11418 Handle<Context> function_context) {
11419 // Try to find the value of 'arguments' to pass as parameter. If it is not
11420 // found (that is the debugged function does not reference 'arguments' and
11421 // does not support eval) then create an 'arguments' object.
11422 int index;
11423 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011424 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011425 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011426 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011427 }
11428 }
11429
11430 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011431 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
11432 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011433 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011434 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011435 }
11436 }
11437
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011438 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
11439
11440 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011441 Handle<JSObject> arguments =
11442 isolate->factory()->NewArgumentsObject(function, length);
11443 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011444
11445 AssertNoAllocation no_gc;
11446 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011447 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011448 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011449 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011450 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011451 return arguments;
11452}
11453
11454
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011455static const char kSourceStr[] =
11456 "(function(arguments,__source__){return eval(__source__);})";
11457
11458
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011459// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011460// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011461// extension part has all the parameters and locals of the function on the
11462// stack frame. A function which calls eval with the code to evaluate is then
11463// compiled in this context and called in this context. As this context
11464// replaces the context of the function on the stack frame a new (empty)
11465// function is created as well to be used as the closure for the context.
11466// This function and the context acts as replacements for the function on the
11467// stack frame presenting the same view of the values of parameters and
11468// local variables as if the piece of JavaScript was evaluated at the point
11469// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011470RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011471 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011472
11473 // Check the execution state and decode arguments frame and source to be
11474 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011475 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011476 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011477 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11478 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011479 if (!maybe_check_result->ToObject(&check_result)) {
11480 return maybe_check_result;
11481 }
11482 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011483 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011484 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11485 CONVERT_ARG_CHECKED(String, source, 3);
11486 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
11487 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011488
11489 // Handle the processing of break.
11490 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011491
11492 // Get the frame where the debugging is performed.
11493 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011494 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011495 JavaScriptFrame* frame = it.frame();
11496 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000011497 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011498 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011499
11500 // Traverse the saved contexts chain to find the active context for the
11501 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011502 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011503 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011504 save = save->prev();
11505 }
11506 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011507 SaveContext savex(isolate);
11508 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011509
11510 // Create the (empty) function replacing the function on the stack frame for
11511 // the purpose of evaluating in the context created below. It is important
11512 // that this function does not describe any parameters and local variables
11513 // in the context. If it does then this will cause problems with the lookup
11514 // in Context::Lookup, where context slots for parameters and local variables
11515 // are looked at before the extension object.
11516 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011517 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11518 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011519 go_between->set_context(function->context());
11520#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011521 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011522 ASSERT(go_between_sinfo.number_of_parameters() == 0);
11523 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
11524#endif
11525
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011526 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011527 Handle<JSObject> local_scope = MaterializeLocalScope(
11528 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011529 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011530
11531 // Allocate a new context for the debug evaluation and set the extension
11532 // object build.
11533 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011534 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11535 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011536 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011537 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011538 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011539 Handle<Context> function_context;
11540 // Get the function's context if it has one.
11541 if (scope_info->HasHeapAllocatedLocals()) {
11542 function_context = Handle<Context>(frame_context->declaration_context());
11543 }
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011544 context = CopyWithContextChain(isolate, go_between, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011545
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011546 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011547 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011548 context =
11549 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011550 }
11551
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011552 // Wrap the evaluation statement in a new function compiled in the newly
11553 // created context. The function has one parameter which has to be called
11554 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011555 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011556 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011557
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011558 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011559 isolate->factory()->NewStringFromAscii(
11560 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011561
11562 // Currently, the eval code will be executed in non-strict mode,
11563 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011564 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011565 Compiler::CompileEval(function_source,
11566 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011567 context->IsGlobalContext(),
11568 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011569 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011570 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011571 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011572
11573 // Invoke the result of the compilation to get the evaluation function.
11574 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011575 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011576 Handle<Object> evaluation_function =
11577 Execution::Call(compiled_function, receiver, 0, NULL,
11578 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011579 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011580
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011581 Handle<Object> arguments = GetArgumentsObject(isolate,
11582 frame, inlined_frame_index,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011583 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011584 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011585
11586 // Invoke the evaluation function and return the result.
11587 const int argc = 2;
11588 Object** argv[argc] = { arguments.location(),
11589 Handle<Object>::cast(source).location() };
11590 Handle<Object> result =
11591 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11592 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011593 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011594
11595 // Skip the global proxy as it has no properties and always delegates to the
11596 // real global object.
11597 if (result->IsJSGlobalProxy()) {
11598 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11599 }
11600
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011601 return *result;
11602}
11603
11604
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011605RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011606 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011607
11608 // Check the execution state and decode arguments frame and source to be
11609 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011610 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011611 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011612 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11613 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011614 if (!maybe_check_result->ToObject(&check_result)) {
11615 return maybe_check_result;
11616 }
11617 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011618 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011619 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011620 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011621
11622 // Handle the processing of break.
11623 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011624
11625 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011626 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011627 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011628 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011629 top = top->prev();
11630 }
11631 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011632 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011633 }
11634
11635 // Get the global context now set to the top context from before the
11636 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011637 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011638
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011639 bool is_global = true;
11640
11641 if (additional_context->IsJSObject()) {
11642 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011643 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11644 isolate->factory()->empty_string(),
11645 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011646 go_between->set_context(*context);
11647 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011648 isolate->factory()->NewFunctionContext(
11649 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011650 context->set_extension(JSObject::cast(*additional_context));
11651 is_global = false;
11652 }
11653
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011654 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011655 // Currently, the eval code will be executed in non-strict mode,
11656 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011657 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011658 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011659 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011660 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011661 Handle<JSFunction>(
11662 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11663 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011664
11665 // Invoke the result of the compilation to get the evaluation function.
11666 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011667 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011668 Handle<Object> result =
11669 Execution::Call(compiled_function, receiver, 0, NULL,
11670 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011671 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011672 return *result;
11673}
11674
11675
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011676RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011677 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011678 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011679
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011680 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011681 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011682
11683 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011684 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011685 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11686 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11687 // because using
11688 // instances->set(i, *GetScriptWrapper(script))
11689 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11690 // already have deferenced the instances handle.
11691 Handle<JSValue> wrapper = GetScriptWrapper(script);
11692 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011693 }
11694
11695 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011696 Handle<JSObject> result =
11697 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011698 Handle<JSArray>::cast(result)->SetContent(*instances);
11699 return *result;
11700}
11701
11702
11703// Helper function used by Runtime_DebugReferencedBy below.
11704static int DebugReferencedBy(JSObject* target,
11705 Object* instance_filter, int max_references,
11706 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011707 JSFunction* arguments_function) {
11708 NoHandleAllocation ha;
11709 AssertNoAllocation no_alloc;
11710
11711 // Iterate the heap.
11712 int count = 0;
11713 JSObject* last = NULL;
11714 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011715 HeapObject* heap_obj = NULL;
11716 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011717 (max_references == 0 || count < max_references)) {
11718 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011719 if (heap_obj->IsJSObject()) {
11720 // Skip context extension objects and argument arrays as these are
11721 // checked in the context of functions using them.
11722 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011723 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011724 obj->map()->constructor() == arguments_function) {
11725 continue;
11726 }
11727
11728 // Check if the JS object has a reference to the object looked for.
11729 if (obj->ReferencesObject(target)) {
11730 // Check instance filter if supplied. This is normally used to avoid
11731 // references from mirror objects (see Runtime_IsInPrototypeChain).
11732 if (!instance_filter->IsUndefined()) {
11733 Object* V = obj;
11734 while (true) {
11735 Object* prototype = V->GetPrototype();
11736 if (prototype->IsNull()) {
11737 break;
11738 }
11739 if (instance_filter == prototype) {
11740 obj = NULL; // Don't add this object.
11741 break;
11742 }
11743 V = prototype;
11744 }
11745 }
11746
11747 if (obj != NULL) {
11748 // Valid reference found add to instance array if supplied an update
11749 // count.
11750 if (instances != NULL && count < instances_size) {
11751 instances->set(count, obj);
11752 }
11753 last = obj;
11754 count++;
11755 }
11756 }
11757 }
11758 }
11759
11760 // Check for circular reference only. This can happen when the object is only
11761 // referenced from mirrors and has a circular reference in which case the
11762 // object is not really alive and would have been garbage collected if not
11763 // referenced from the mirror.
11764 if (count == 1 && last == target) {
11765 count = 0;
11766 }
11767
11768 // Return the number of referencing objects found.
11769 return count;
11770}
11771
11772
11773// Scan the heap for objects with direct references to an object
11774// args[0]: the object to find references to
11775// args[1]: constructor function for instances to exclude (Mirror)
11776// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011777RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011778 ASSERT(args.length() == 3);
11779
11780 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011781 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011782
11783 // Check parameters.
11784 CONVERT_CHECKED(JSObject, target, args[0]);
11785 Object* instance_filter = args[1];
11786 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11787 instance_filter->IsJSObject());
11788 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11789 RUNTIME_ASSERT(max_references >= 0);
11790
11791 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011792 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011793 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011794 JSFunction* arguments_function =
11795 JSFunction::cast(arguments_boilerplate->map()->constructor());
11796
11797 // Get the number of referencing objects.
11798 int count;
11799 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011800 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011801
11802 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011803 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011804 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011805 if (!maybe_object->ToObject(&object)) return maybe_object;
11806 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011807 FixedArray* instances = FixedArray::cast(object);
11808
11809 // Fill the referencing objects.
11810 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011811 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011812
11813 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011814 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011815 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11816 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011817 if (!maybe_result->ToObject(&result)) return maybe_result;
11818 }
11819 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011820 return result;
11821}
11822
11823
11824// Helper function used by Runtime_DebugConstructedBy below.
11825static int DebugConstructedBy(JSFunction* constructor, int max_references,
11826 FixedArray* instances, int instances_size) {
11827 AssertNoAllocation no_alloc;
11828
11829 // Iterate the heap.
11830 int count = 0;
11831 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011832 HeapObject* heap_obj = NULL;
11833 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011834 (max_references == 0 || count < max_references)) {
11835 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011836 if (heap_obj->IsJSObject()) {
11837 JSObject* obj = JSObject::cast(heap_obj);
11838 if (obj->map()->constructor() == constructor) {
11839 // Valid reference found add to instance array if supplied an update
11840 // count.
11841 if (instances != NULL && count < instances_size) {
11842 instances->set(count, obj);
11843 }
11844 count++;
11845 }
11846 }
11847 }
11848
11849 // Return the number of referencing objects found.
11850 return count;
11851}
11852
11853
11854// Scan the heap for objects constructed by a specific function.
11855// args[0]: the constructor to find instances of
11856// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011857RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011858 ASSERT(args.length() == 2);
11859
11860 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011861 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011862
11863 // Check parameters.
11864 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11865 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11866 RUNTIME_ASSERT(max_references >= 0);
11867
11868 // Get the number of referencing objects.
11869 int count;
11870 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11871
11872 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011873 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011874 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011875 if (!maybe_object->ToObject(&object)) return maybe_object;
11876 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011877 FixedArray* instances = FixedArray::cast(object);
11878
11879 // Fill the referencing objects.
11880 count = DebugConstructedBy(constructor, max_references, instances, count);
11881
11882 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011883 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011884 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11885 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011886 if (!maybe_result->ToObject(&result)) return maybe_result;
11887 }
11888 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011889 return result;
11890}
11891
11892
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011893// Find the effective prototype object as returned by __proto__.
11894// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011895RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011896 ASSERT(args.length() == 1);
11897
11898 CONVERT_CHECKED(JSObject, obj, args[0]);
11899
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011900 // Use the __proto__ accessor.
11901 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011902}
11903
11904
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011905RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011906 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011907 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011908 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011909}
11910
11911
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011912RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011913#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011914 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011915 ASSERT(args.length() == 1);
11916 // Get the function and make sure it is compiled.
11917 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011918 Handle<SharedFunctionInfo> shared(func->shared());
11919 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011920 return Failure::Exception();
11921 }
11922 func->code()->PrintLn();
11923#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011924 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011925}
ager@chromium.org9085a012009-05-11 19:22:57 +000011926
11927
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011928RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011929#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011930 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011931 ASSERT(args.length() == 1);
11932 // Get the function and make sure it is compiled.
11933 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011934 Handle<SharedFunctionInfo> shared(func->shared());
11935 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011936 return Failure::Exception();
11937 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011938 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011939#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011940 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011941}
11942
11943
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011944RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011945 NoHandleAllocation ha;
11946 ASSERT(args.length() == 1);
11947
11948 CONVERT_CHECKED(JSFunction, f, args[0]);
11949 return f->shared()->inferred_name();
11950}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011951
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011952
11953static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011954 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011955 AssertNoAllocation no_allocations;
11956
11957 int counter = 0;
11958 int buffer_size = buffer->length();
11959 HeapIterator iterator;
11960 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11961 ASSERT(obj != NULL);
11962 if (!obj->IsSharedFunctionInfo()) {
11963 continue;
11964 }
11965 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11966 if (shared->script() != script) {
11967 continue;
11968 }
11969 if (counter < buffer_size) {
11970 buffer->set(counter, shared);
11971 }
11972 counter++;
11973 }
11974 return counter;
11975}
11976
11977// For a script finds all SharedFunctionInfo's in the heap that points
11978// to this script. Returns JSArray of SharedFunctionInfo wrapped
11979// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011980RUNTIME_FUNCTION(MaybeObject*,
11981 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011982 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011983 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011984 CONVERT_CHECKED(JSValue, script_value, args[0]);
11985
11986 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11987
11988 const int kBufferSize = 32;
11989
11990 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011991 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011992 int number = FindSharedFunctionInfosForScript(*script, *array);
11993 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011994 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011995 FindSharedFunctionInfosForScript(*script, *array);
11996 }
11997
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011998 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011999 result->set_length(Smi::FromInt(number));
12000
12001 LiveEdit::WrapSharedFunctionInfos(result);
12002
12003 return *result;
12004}
12005
12006// For a script calculates compilation information about all its functions.
12007// The script source is explicitly specified by the second argument.
12008// The source of the actual script is not used, however it is important that
12009// all generated code keeps references to this particular instance of script.
12010// Returns a JSArray of compilation infos. The array is ordered so that
12011// each function with all its descendant is always stored in a continues range
12012// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012013RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012014 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012015 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012016 CONVERT_CHECKED(JSValue, script, args[0]);
12017 CONVERT_ARG_CHECKED(String, source, 1);
12018 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12019
12020 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12021
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012022 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012023 return Failure::Exception();
12024 }
12025
12026 return result;
12027}
12028
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012029// Changes the source of the script to a new_source.
12030// If old_script_name is provided (i.e. is a String), also creates a copy of
12031// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012032RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012033 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012034 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012035 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12036 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012037 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012038
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012039 CONVERT_CHECKED(Script, original_script_pointer,
12040 original_script_value->value());
12041 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012042
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012043 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12044 new_source,
12045 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012046
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012047 if (old_script->IsScript()) {
12048 Handle<Script> script_handle(Script::cast(old_script));
12049 return *(GetScriptWrapper(script_handle));
12050 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012051 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012052 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012053}
12054
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012056RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012057 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012058 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012059 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12060 return LiveEdit::FunctionSourceUpdated(shared_info);
12061}
12062
12063
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012064// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012065RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012066 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012067 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012068 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12069 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12070
ager@chromium.orgac091b72010-05-05 07:34:42 +000012071 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012072}
12073
12074// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012075RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012076 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012077 HandleScope scope(isolate);
12078 Handle<Object> function_object(args[0], isolate);
12079 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012080
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012081 if (function_object->IsJSValue()) {
12082 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12083 if (script_object->IsJSValue()) {
12084 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012085 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012086 }
12087
12088 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12089 } else {
12090 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12091 // and we check it in this function.
12092 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012093
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012094 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012095}
12096
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012097
12098// In a code of a parent function replaces original function as embedded object
12099// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012100RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012101 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012102 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012103
12104 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12105 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12106 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12107
12108 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12109 subst_wrapper);
12110
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012111 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012112}
12113
12114
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012115// Updates positions of a shared function info (first parameter) according
12116// to script source change. Text change is described in second parameter as
12117// array of groups of 3 numbers:
12118// (change_begin, change_end, change_end_new_position).
12119// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012120RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012121 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012122 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012123 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12124 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12125
ager@chromium.orgac091b72010-05-05 07:34:42 +000012126 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012127}
12128
12129
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012130// For array of SharedFunctionInfo's (each wrapped in JSValue)
12131// checks that none of them have activations on stacks (of any thread).
12132// Returns array of the same length with corresponding results of
12133// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012134RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012135 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012136 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012137 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012138 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012139
ager@chromium.org357bf652010-04-12 11:30:10 +000012140 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012141}
12142
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012143// Compares 2 strings line-by-line, then token-wise and returns diff in form
12144// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12145// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012146RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012147 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012148 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012149 CONVERT_ARG_CHECKED(String, s1, 0);
12150 CONVERT_ARG_CHECKED(String, s2, 1);
12151
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012152 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012153}
12154
12155
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012156// A testing entry. Returns statement position which is the closest to
12157// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012158RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012159 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012160 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012161 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12162 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12163
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012164 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012165
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012166 if (code->kind() != Code::FUNCTION &&
12167 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012168 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012169 }
12170
12171 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012172 int closest_pc = 0;
12173 int distance = kMaxInt;
12174 while (!it.done()) {
12175 int statement_position = static_cast<int>(it.rinfo()->data());
12176 // Check if this break point is closer that what was previously found.
12177 if (source_position <= statement_position &&
12178 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012179 closest_pc =
12180 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012181 distance = statement_position - source_position;
12182 // Check whether we can't get any closer.
12183 if (distance == 0) break;
12184 }
12185 it.next();
12186 }
12187
12188 return Smi::FromInt(closest_pc);
12189}
12190
12191
ager@chromium.org357bf652010-04-12 11:30:10 +000012192// Calls specified function with or without entering the debugger.
12193// This is used in unit tests to run code as if debugger is entered or simply
12194// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012195RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012196 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012197 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012198 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12199 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12200
12201 Handle<Object> result;
12202 bool pending_exception;
12203 {
12204 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012205 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012206 &pending_exception);
12207 } else {
12208 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012209 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012210 &pending_exception);
12211 }
12212 }
12213 if (!pending_exception) {
12214 return *result;
12215 } else {
12216 return Failure::Exception();
12217 }
12218}
12219
12220
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012221// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012222RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012223 CONVERT_CHECKED(String, arg, args[0]);
12224 SmartPointer<char> flags =
12225 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12226 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012227 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012228}
12229
12230
12231// Performs a GC.
12232// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012233RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012234 isolate->heap()->CollectAllGarbage(true);
12235 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012236}
12237
12238
12239// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012240RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012241 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012242 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012243 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012244 }
12245 return Smi::FromInt(usage);
12246}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012247
12248
12249// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012250RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012251#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012252 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012253#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012254 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012255#endif
12256}
12257
12258
12259// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012260RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012261#ifdef LIVE_OBJECT_LIST
12262 return LiveObjectList::Capture();
12263#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012264 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012265#endif
12266}
12267
12268
12269// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012270RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012271#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012272 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012273 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012274 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012275#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012276 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012277#endif
12278}
12279
12280
12281// Generates the response to a debugger request for a dump of the objects
12282// contained in the difference between the captured live object lists
12283// specified by id1 and id2.
12284// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12285// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012286RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012287#ifdef LIVE_OBJECT_LIST
12288 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012289 CONVERT_SMI_ARG_CHECKED(id1, 0);
12290 CONVERT_SMI_ARG_CHECKED(id2, 1);
12291 CONVERT_SMI_ARG_CHECKED(start, 2);
12292 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012293 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12294 EnterDebugger enter_debugger;
12295 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12296#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012297 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012298#endif
12299}
12300
12301
12302// Gets the specified object as requested by the debugger.
12303// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012304RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012305#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012306 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012307 Object* result = LiveObjectList::GetObj(obj_id);
12308 return result;
12309#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012310 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012311#endif
12312}
12313
12314
12315// Gets the obj id for the specified address if valid.
12316// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012317RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012318#ifdef LIVE_OBJECT_LIST
12319 HandleScope scope;
12320 CONVERT_ARG_CHECKED(String, address, 0);
12321 Object* result = LiveObjectList::GetObjId(address);
12322 return result;
12323#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012324 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012325#endif
12326}
12327
12328
12329// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012330RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012331#ifdef LIVE_OBJECT_LIST
12332 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012333 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012334 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12335 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12336 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12337 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12338 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12339
12340 Handle<JSObject> instance_filter;
12341 if (args[1]->IsJSObject()) {
12342 instance_filter = args.at<JSObject>(1);
12343 }
12344 bool verbose = false;
12345 if (args[2]->IsBoolean()) {
12346 verbose = args[2]->IsTrue();
12347 }
12348 int start = 0;
12349 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012350 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012351 }
12352 int limit = Smi::kMaxValue;
12353 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012354 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012355 }
12356
12357 return LiveObjectList::GetObjRetainers(obj_id,
12358 instance_filter,
12359 verbose,
12360 start,
12361 limit,
12362 filter_obj);
12363#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012364 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012365#endif
12366}
12367
12368
12369// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012370RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012371#ifdef LIVE_OBJECT_LIST
12372 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012373 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12374 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012375 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12376
12377 Handle<JSObject> instance_filter;
12378 if (args[2]->IsJSObject()) {
12379 instance_filter = args.at<JSObject>(2);
12380 }
12381
12382 Object* result =
12383 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12384 return result;
12385#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012386 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012387#endif
12388}
12389
12390
12391// Generates the response to a debugger request for a list of all
12392// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012393RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012394#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012395 CONVERT_SMI_ARG_CHECKED(start, 0);
12396 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012397 return LiveObjectList::Info(start, count);
12398#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012399 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012400#endif
12401}
12402
12403
12404// Gets a dump of the specified object as requested by the debugger.
12405// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012406RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012407#ifdef LIVE_OBJECT_LIST
12408 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012409 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012410 Object* result = LiveObjectList::PrintObj(obj_id);
12411 return result;
12412#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012413 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012414#endif
12415}
12416
12417
12418// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012419RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012420#ifdef LIVE_OBJECT_LIST
12421 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012422 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012423#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012424 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012425#endif
12426}
12427
12428
12429// Generates the response to a debugger request for a summary of the types
12430// of objects in the difference between the captured live object lists
12431// specified by id1 and id2.
12432// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12433// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012434RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012435#ifdef LIVE_OBJECT_LIST
12436 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012437 CONVERT_SMI_ARG_CHECKED(id1, 0);
12438 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012439 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
12440
12441 EnterDebugger enter_debugger;
12442 return LiveObjectList::Summarize(id1, id2, filter_obj);
12443#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012444 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012445#endif
12446}
12447
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012448#endif // ENABLE_DEBUGGER_SUPPORT
12449
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012450
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012451RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012452 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012453 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012454 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012455}
12456
12457
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012458RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012459 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012460 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012461 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012462}
12463
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012464
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012465// Finds the script object from the script data. NOTE: This operation uses
12466// heap traversal to find the function generated for the source position
12467// for the requested break point. For lazily compiled functions several heap
12468// traversals might be required rendering this operation as a rather slow
12469// operation. However for setting break points which is normally done through
12470// some kind of user interaction the performance is not crucial.
12471static Handle<Object> Runtime_GetScriptFromScriptName(
12472 Handle<String> script_name) {
12473 // Scan the heap for Script objects to find the script with the requested
12474 // script data.
12475 Handle<Script> script;
12476 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012477 HeapObject* obj = NULL;
12478 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012479 // If a script is found check if it has the script data requested.
12480 if (obj->IsScript()) {
12481 if (Script::cast(obj)->name()->IsString()) {
12482 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12483 script = Handle<Script>(Script::cast(obj));
12484 }
12485 }
12486 }
12487 }
12488
12489 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012490 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012491
12492 // Return the script found.
12493 return GetScriptWrapper(script);
12494}
12495
12496
12497// Get the script object from script data. NOTE: Regarding performance
12498// see the NOTE for GetScriptFromScriptData.
12499// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012500RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012501 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012502
12503 ASSERT(args.length() == 1);
12504
12505 CONVERT_CHECKED(String, script_name, args[0]);
12506
12507 // Find the requested script.
12508 Handle<Object> result =
12509 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12510 return *result;
12511}
12512
12513
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012514// Determines whether the given stack frame should be displayed in
12515// a stack trace. The caller is the error constructor that asked
12516// for the stack trace to be collected. The first time a construct
12517// call to this function is encountered it is skipped. The seen_caller
12518// in/out parameter is used to remember if the caller has been seen
12519// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012520static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12521 Object* caller,
12522 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012523 // Only display JS frames.
12524 if (!raw_frame->is_java_script())
12525 return false;
12526 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12527 Object* raw_fun = frame->function();
12528 // Not sure when this can happen but skip it just in case.
12529 if (!raw_fun->IsJSFunction())
12530 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012531 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012532 *seen_caller = true;
12533 return false;
12534 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012535 // Skip all frames until we've seen the caller.
12536 if (!(*seen_caller)) return false;
12537 // Also, skip the most obvious builtin calls. We recognize builtins
12538 // as (1) functions called with the builtins object as the receiver and
12539 // as (2) functions from native scripts called with undefined as the
12540 // receiver (direct calls to helper functions in the builtins
12541 // code). Some builtin calls (such as Number.ADD which is invoked
12542 // using 'call') are very difficult to recognize so we're leaving
12543 // them in for now.
12544 if (frame->receiver()->IsJSBuiltinsObject()) {
12545 return false;
12546 }
12547 JSFunction* fun = JSFunction::cast(raw_fun);
12548 Object* raw_script = fun->shared()->script();
12549 if (frame->receiver()->IsUndefined() && raw_script->IsScript()) {
12550 int script_type = Script::cast(raw_script)->type()->value();
12551 return script_type != Script::TYPE_NATIVE;
12552 }
12553 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012554}
12555
12556
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012557// Collect the raw data for a stack trace. Returns an array of 4
12558// element segments each containing a receiver, function, code and
12559// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012560RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012561 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012562 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012563 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12564
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012565 HandleScope scope(isolate);
12566 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012567
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012568 limit = Max(limit, 0); // Ensure that limit is not negative.
12569 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012570 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012571 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012572
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012573 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012574 // If the caller parameter is a function we skip frames until we're
12575 // under it before starting to collect.
12576 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012577 int cursor = 0;
12578 int frames_seen = 0;
12579 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012580 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012581 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012582 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012583 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012584 // Set initial size to the maximum inlining level + 1 for the outermost
12585 // function.
12586 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012587 frame->Summarize(&frames);
12588 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012589 if (cursor + 4 > elements->length()) {
12590 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12591 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012592 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012593 for (int i = 0; i < cursor; i++) {
12594 new_elements->set(i, elements->get(i));
12595 }
12596 elements = new_elements;
12597 }
12598 ASSERT(cursor + 4 <= elements->length());
12599
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012600 Handle<Object> recv = frames[i].receiver();
12601 Handle<JSFunction> fun = frames[i].function();
12602 Handle<Code> code = frames[i].code();
12603 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012604 elements->set(cursor++, *recv);
12605 elements->set(cursor++, *fun);
12606 elements->set(cursor++, *code);
12607 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012608 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012609 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012610 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012611 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012612 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012613 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012614 return *result;
12615}
12616
12617
ager@chromium.org3811b432009-10-28 14:53:37 +000012618// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012619RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012620 ASSERT_EQ(args.length(), 0);
12621
12622 NoHandleAllocation ha;
12623
12624 const char* version_string = v8::V8::GetVersion();
12625
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012626 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12627 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012628}
12629
12630
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012631RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012632 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012633 OS::PrintError("abort: %s\n",
12634 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012635 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012636 OS::Abort();
12637 UNREACHABLE();
12638 return NULL;
12639}
12640
12641
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012642RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012643 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012644 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012645 Object* key = args[1];
12646
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012647 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012648 Object* o = cache->get(finger_index);
12649 if (o == key) {
12650 // The fastest case: hit the same place again.
12651 return cache->get(finger_index + 1);
12652 }
12653
12654 for (int i = finger_index - 2;
12655 i >= JSFunctionResultCache::kEntriesIndex;
12656 i -= 2) {
12657 o = cache->get(i);
12658 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012659 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012660 return cache->get(i + 1);
12661 }
12662 }
12663
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012664 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012665 ASSERT(size <= cache->length());
12666
12667 for (int i = size - 2; i > finger_index; i -= 2) {
12668 o = cache->get(i);
12669 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012670 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012671 return cache->get(i + 1);
12672 }
12673 }
12674
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012675 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012676 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012677
12678 Handle<JSFunctionResultCache> cache_handle(cache);
12679 Handle<Object> key_handle(key);
12680 Handle<Object> value;
12681 {
12682 Handle<JSFunction> factory(JSFunction::cast(
12683 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12684 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012685 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012686 // This handle is nor shared, nor used later, so it's safe.
12687 Object** argv[] = { key_handle.location() };
12688 bool pending_exception = false;
12689 value = Execution::Call(factory,
12690 receiver,
12691 1,
12692 argv,
12693 &pending_exception);
12694 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012695 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012696
12697#ifdef DEBUG
12698 cache_handle->JSFunctionResultCacheVerify();
12699#endif
12700
12701 // Function invocation may have cleared the cache. Reread all the data.
12702 finger_index = cache_handle->finger_index();
12703 size = cache_handle->size();
12704
12705 // If we have spare room, put new data into it, otherwise evict post finger
12706 // entry which is likely to be the least recently used.
12707 int index = -1;
12708 if (size < cache_handle->length()) {
12709 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12710 index = size;
12711 } else {
12712 index = finger_index + JSFunctionResultCache::kEntrySize;
12713 if (index == cache_handle->length()) {
12714 index = JSFunctionResultCache::kEntriesIndex;
12715 }
12716 }
12717
12718 ASSERT(index % 2 == 0);
12719 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12720 ASSERT(index < cache_handle->length());
12721
12722 cache_handle->set(index, *key_handle);
12723 cache_handle->set(index + 1, *value);
12724 cache_handle->set_finger_index(index);
12725
12726#ifdef DEBUG
12727 cache_handle->JSFunctionResultCacheVerify();
12728#endif
12729
12730 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012731}
12732
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012733
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012734RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012735 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012736 CONVERT_ARG_CHECKED(String, type, 0);
12737 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012738 return *isolate->factory()->NewJSMessageObject(
12739 type,
12740 arguments,
12741 0,
12742 0,
12743 isolate->factory()->undefined_value(),
12744 isolate->factory()->undefined_value(),
12745 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012746}
12747
12748
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012749RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012750 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12751 return message->type();
12752}
12753
12754
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012755RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012756 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12757 return message->arguments();
12758}
12759
12760
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012761RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012762 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12763 return Smi::FromInt(message->start_position());
12764}
12765
12766
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012767RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012768 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12769 return message->script();
12770}
12771
12772
kasper.lund44510672008-07-25 07:37:58 +000012773#ifdef DEBUG
12774// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12775// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012776RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012777 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012778 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012779#define COUNT_ENTRY(Name, argc, ressize) + 1
12780 int entry_count = 0
12781 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12782 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12783 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12784#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012785 Factory* factory = isolate->factory();
12786 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012787 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012788 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012789#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012790 { \
12791 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012792 Handle<String> name; \
12793 /* Inline runtime functions have an underscore in front of the name. */ \
12794 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012795 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012796 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12797 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012798 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012799 Vector<const char>(#Name, StrLength(#Name))); \
12800 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012801 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012802 pair_elements->set(0, *name); \
12803 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012804 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012805 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012806 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012807 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012808 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012809 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012810 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012811 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012812#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012813 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012814 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012815 return *result;
12816}
kasper.lund44510672008-07-25 07:37:58 +000012817#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012818
12819
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012820RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012821 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012822 CONVERT_CHECKED(String, format, args[0]);
12823 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000012824 String::FlatContent format_content = format->GetFlatContent();
12825 RUNTIME_ASSERT(format_content.IsAscii());
12826 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012827 LOGGER->LogRuntime(chars, elms);
12828 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012829}
12830
12831
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012832RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012833 UNREACHABLE(); // implemented as macro in the parser
12834 return NULL;
12835}
12836
12837
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012838#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
12839 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
12840 CONVERT_CHECKED(JSObject, obj, args[0]); \
12841 return isolate->heap()->ToBoolean(obj->Has##Name()); \
12842 }
12843
12844ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
12845ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
12846ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
12847ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
12848ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
12849ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
12850ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
12851ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
12852ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
12853ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
12854ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
12855ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
12856ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
12857
12858#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
12859
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012860// ----------------------------------------------------------------------------
12861// Implementation of Runtime
12862
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012863#define F(name, number_of_args, result_size) \
12864 { Runtime::k##name, Runtime::RUNTIME, #name, \
12865 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012866
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012867
12868#define I(name, number_of_args, result_size) \
12869 { Runtime::kInline##name, Runtime::INLINE, \
12870 "_" #name, NULL, number_of_args, result_size },
12871
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012872static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012873 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012874 INLINE_FUNCTION_LIST(I)
12875 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012876};
12877
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012878
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012879MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12880 Object* dictionary) {
12881 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012882 ASSERT(dictionary != NULL);
12883 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12884 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012885 Object* name_symbol;
12886 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012887 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012888 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12889 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012890 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012891 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12892 String::cast(name_symbol),
12893 Smi::FromInt(i),
12894 PropertyDetails(NONE, NORMAL));
12895 if (!maybe_dictionary->ToObject(&dictionary)) {
12896 // Non-recoverable failure. Calling code must restart heap
12897 // initialization.
12898 return maybe_dictionary;
12899 }
12900 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012901 }
12902 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012903}
12904
12905
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012906const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12907 Heap* heap = name->GetHeap();
12908 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012909 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012910 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012911 int function_index = Smi::cast(smi_index)->value();
12912 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012913 }
12914 return NULL;
12915}
12916
12917
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012918const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012919 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12920}
12921
12922
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012923void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012924 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012925 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012926 if (failure->IsRetryAfterGC()) {
12927 // Try to do a garbage collection; ignore it if it fails. The C
12928 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012929 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012930 } else {
12931 // Handle last resort GC and make sure to allow future allocations
12932 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012933 isolate->counters()->gc_last_resort_from_js()->Increment();
12934 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012935 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012936}
12937
12938
12939} } // namespace v8::internal