blob: 802fd6845d0204cabeba1de5cd070261ebbf3e66 [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);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000686 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
687 Object* obj = input_obj;
688 // We don't expect access checks to be needed on JSProxy objects.
689 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000690 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000691 if (obj->IsAccessCheckNeeded() &&
692 !isolate->MayNamedAccess(JSObject::cast(obj),
693 isolate->heap()->Proto_symbol(),
694 v8::ACCESS_GET)) {
695 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
696 return isolate->heap()->undefined_value();
697 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000698 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000699 } while (obj->IsJSObject() &&
700 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000701 return obj;
702}
703
704
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000705RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000706 NoHandleAllocation ha;
707 ASSERT(args.length() == 2);
708 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
709 Object* O = args[0];
710 Object* V = args[1];
711 while (true) {
712 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000713 if (prototype->IsNull()) return isolate->heap()->false_value();
714 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000715 V = prototype;
716 }
717}
718
719
ager@chromium.org9085a012009-05-11 19:22:57 +0000720// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000721RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000722 NoHandleAllocation ha;
723 ASSERT(args.length() == 2);
724 CONVERT_CHECKED(JSObject, jsobject, args[0]);
725 CONVERT_CHECKED(JSObject, proto, args[1]);
726
727 // Sanity checks. The old prototype (that we are replacing) could
728 // theoretically be null, but if it is not null then check that we
729 // didn't already install a hidden prototype here.
730 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
731 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
732 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
733
734 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000735 Object* map_or_failure;
736 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
737 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
738 return maybe_map_or_failure;
739 }
740 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000741 Map* new_proto_map = Map::cast(map_or_failure);
742
lrn@chromium.org303ada72010-10-27 09:33:13 +0000743 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
744 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
745 return maybe_map_or_failure;
746 }
747 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000748 Map* new_map = Map::cast(map_or_failure);
749
750 // Set proto's prototype to be the old prototype of the object.
751 new_proto_map->set_prototype(jsobject->GetPrototype());
752 proto->set_map(new_proto_map);
753 new_proto_map->set_is_hidden_prototype();
754
755 // Set the object's prototype to proto.
756 new_map->set_prototype(proto);
757 jsobject->set_map(new_map);
758
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000759 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000760}
761
762
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000763RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000764 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000765 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000766 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000767 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000768}
769
770
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000771// Recursively traverses hidden prototypes if property is not found
772static void GetOwnPropertyImplementation(JSObject* obj,
773 String* name,
774 LookupResult* result) {
775 obj->LocalLookupRealNamedProperty(name, result);
776
777 if (!result->IsProperty()) {
778 Object* proto = obj->GetPrototype();
779 if (proto->IsJSObject() &&
780 JSObject::cast(proto)->map()->is_hidden_prototype())
781 GetOwnPropertyImplementation(JSObject::cast(proto),
782 name, result);
783 }
784}
785
786
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000787static bool CheckAccessException(LookupResult* result,
788 v8::AccessType access_type) {
789 if (result->type() == CALLBACKS) {
790 Object* callback = result->GetCallbackObject();
791 if (callback->IsAccessorInfo()) {
792 AccessorInfo* info = AccessorInfo::cast(callback);
793 bool can_access =
794 (access_type == v8::ACCESS_HAS &&
795 (info->all_can_read() || info->all_can_write())) ||
796 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
797 (access_type == v8::ACCESS_SET && info->all_can_write());
798 return can_access;
799 }
800 }
801
802 return false;
803}
804
805
806static bool CheckAccess(JSObject* obj,
807 String* name,
808 LookupResult* result,
809 v8::AccessType access_type) {
810 ASSERT(result->IsProperty());
811
812 JSObject* holder = result->holder();
813 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000814 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000815 while (true) {
816 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000817 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000818 // Access check callback denied the access, but some properties
819 // can have a special permissions which override callbacks descision
820 // (currently see v8::AccessControl).
821 break;
822 }
823
824 if (current == holder) {
825 return true;
826 }
827
828 current = JSObject::cast(current->GetPrototype());
829 }
830
831 // API callbacks can have per callback access exceptions.
832 switch (result->type()) {
833 case CALLBACKS: {
834 if (CheckAccessException(result, access_type)) {
835 return true;
836 }
837 break;
838 }
839 case INTERCEPTOR: {
840 // If the object has an interceptor, try real named properties.
841 // Overwrite the result to fetch the correct property later.
842 holder->LookupRealNamedProperty(name, result);
843 if (result->IsProperty()) {
844 if (CheckAccessException(result, access_type)) {
845 return true;
846 }
847 }
848 break;
849 }
850 default:
851 break;
852 }
853
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000854 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000855 return false;
856}
857
858
859// TODO(1095): we should traverse hidden prototype hierachy as well.
860static bool CheckElementAccess(JSObject* obj,
861 uint32_t index,
862 v8::AccessType access_type) {
863 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000864 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000865 return false;
866 }
867
868 return true;
869}
870
871
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000872// Enumerator used as indices into the array returned from GetOwnProperty
873enum PropertyDescriptorIndices {
874 IS_ACCESSOR_INDEX,
875 VALUE_INDEX,
876 GETTER_INDEX,
877 SETTER_INDEX,
878 WRITABLE_INDEX,
879 ENUMERABLE_INDEX,
880 CONFIGURABLE_INDEX,
881 DESCRIPTOR_SIZE
882};
883
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000884// Returns an array with the property description:
885// if args[1] is not a property on args[0]
886// returns undefined
887// if args[1] is a data property on args[0]
888// [false, value, Writeable, Enumerable, Configurable]
889// if args[1] is an accessor on args[0]
890// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000891RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000892 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000893 Heap* heap = isolate->heap();
894 HandleScope scope(isolate);
895 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
896 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000897 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000898 CONVERT_ARG_CHECKED(JSObject, obj, 0);
899 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000900
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000901 // This could be an element.
902 uint32_t index;
903 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000904 switch (obj->HasLocalElement(index)) {
905 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000906 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000907
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000908 case JSObject::STRING_CHARACTER_ELEMENT: {
909 // Special handling of string objects according to ECMAScript 5
910 // 15.5.5.2. Note that this might be a string object with elements
911 // other than the actual string value. This is covered by the
912 // subsequent cases.
913 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
914 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000915 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000916
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000917 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000918 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000919 elms->set(WRITABLE_INDEX, heap->false_value());
920 elms->set(ENUMERABLE_INDEX, heap->false_value());
921 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000922 return *desc;
923 }
924
925 case JSObject::INTERCEPTED_ELEMENT:
926 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000927 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000928 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000929 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000930 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000931 elms->set(WRITABLE_INDEX, heap->true_value());
932 elms->set(ENUMERABLE_INDEX, heap->true_value());
933 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000934 return *desc;
935 }
936
937 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000938 Handle<JSObject> holder = obj;
939 if (obj->IsJSGlobalProxy()) {
940 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000941 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000942 ASSERT(proto->IsJSGlobalObject());
943 holder = Handle<JSObject>(JSObject::cast(proto));
944 }
whesse@chromium.org7b260152011-06-20 15:33:18 +0000945 FixedArray* elements = FixedArray::cast(holder->elements());
946 NumberDictionary* dictionary = NULL;
947 if (elements->map() == heap->non_strict_arguments_elements_map()) {
948 dictionary = NumberDictionary::cast(elements->get(1));
949 } else {
950 dictionary = NumberDictionary::cast(elements);
951 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000952 int entry = dictionary->FindEntry(index);
953 ASSERT(entry != NumberDictionary::kNotFound);
954 PropertyDetails details = dictionary->DetailsAt(entry);
955 switch (details.type()) {
956 case CALLBACKS: {
957 // This is an accessor property with getter and/or setter.
958 FixedArray* callbacks =
959 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000960 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000961 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
962 elms->set(GETTER_INDEX, callbacks->get(0));
963 }
964 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
965 elms->set(SETTER_INDEX, callbacks->get(1));
966 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000967 break;
968 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000969 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000970 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000971 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000972 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000973 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000974 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000975 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000976 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000977 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000978 default:
979 UNREACHABLE();
980 break;
981 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000982 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
983 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000984 return *desc;
985 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000986 }
987 }
988
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000989 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000990 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000991
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000992 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000993 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000994 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000995
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000996 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000997 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000998 }
999
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001000 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1001 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001002
1003 bool is_js_accessor = (result.type() == CALLBACKS) &&
1004 (result.GetCallbackObject()->IsFixedArray());
1005
1006 if (is_js_accessor) {
1007 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001008 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001009
1010 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
1011 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1012 elms->set(GETTER_INDEX, structure->get(0));
1013 }
1014 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1015 elms->set(SETTER_INDEX, structure->get(1));
1016 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001017 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001018 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1019 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001020
1021 PropertyAttributes attrs;
1022 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001023 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001024 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1025 if (!maybe_value->ToObject(&value)) return maybe_value;
1026 }
1027 elms->set(VALUE_INDEX, value);
1028 }
1029
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001030 return *desc;
1031}
1032
1033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001034RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001035 ASSERT(args.length() == 1);
1036 CONVERT_CHECKED(JSObject, obj, args[0]);
1037 return obj->PreventExtensions();
1038}
1039
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001040
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001041RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001042 ASSERT(args.length() == 1);
1043 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001044 if (obj->IsJSGlobalProxy()) {
1045 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001046 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001047 ASSERT(proto->IsJSGlobalObject());
1048 obj = JSObject::cast(proto);
1049 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001050 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001051}
1052
1053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001054RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001055 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001056 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001057 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1058 CONVERT_ARG_CHECKED(String, pattern, 1);
1059 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001060 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1061 if (result.is_null()) return Failure::Exception();
1062 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001063}
1064
1065
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001066RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001067 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001068 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001069 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001070 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001071}
1072
1073
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001074RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001075 ASSERT(args.length() == 1);
1076 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001077 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001078 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001079}
1080
1081
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001082RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001083 ASSERT(args.length() == 2);
1084 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001085 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001086 int index = field->value();
1087 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1088 InstanceType type = templ->map()->instance_type();
1089 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1090 type == OBJECT_TEMPLATE_INFO_TYPE);
1091 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001092 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001093 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1094 } else {
1095 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1096 }
1097 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098}
1099
1100
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001101RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001102 ASSERT(args.length() == 1);
1103 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001104 Map* old_map = object->map();
1105 bool needs_access_checks = old_map->is_access_check_needed();
1106 if (needs_access_checks) {
1107 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001108 Object* new_map;
1109 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1110 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1111 }
ager@chromium.org32912102009-01-16 10:38:43 +00001112
1113 Map::cast(new_map)->set_is_access_check_needed(false);
1114 object->set_map(Map::cast(new_map));
1115 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001116 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001117}
1118
1119
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001120RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001121 ASSERT(args.length() == 1);
1122 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001123 Map* old_map = object->map();
1124 if (!old_map->is_access_check_needed()) {
1125 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001126 Object* new_map;
1127 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1128 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1129 }
ager@chromium.org32912102009-01-16 10:38:43 +00001130
1131 Map::cast(new_map)->set_is_access_check_needed(true);
1132 object->set_map(Map::cast(new_map));
1133 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001134 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001135}
1136
1137
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001138static Failure* ThrowRedeclarationError(Isolate* isolate,
1139 const char* type,
1140 Handle<String> name) {
1141 HandleScope scope(isolate);
1142 Handle<Object> type_handle =
1143 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001144 Handle<Object> args[2] = { type_handle, name };
1145 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001146 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1147 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001148}
1149
1150
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001151RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001152 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001153 HandleScope scope(isolate);
1154 Handle<GlobalObject> global = Handle<GlobalObject>(
1155 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001156
ager@chromium.org3811b432009-10-28 14:53:37 +00001157 Handle<Context> context = args.at<Context>(0);
1158 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001159 bool is_eval = args.smi_at(2) == 1;
1160 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001161 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001162
1163 // Compute the property attributes. According to ECMA-262, section
1164 // 13, page 71, the property must be read-only and
1165 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1166 // property as read-only, so we don't either.
1167 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1168
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001169 // Traverse the name/value pairs and set the properties.
1170 int length = pairs->length();
1171 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001172 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001173 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001174 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001175
1176 // We have to declare a global const property. To capture we only
1177 // assign to it when evaluating the assignment for "const x =
1178 // <expr>" the initial value is the hole.
1179 bool is_const_property = value->IsTheHole();
1180
1181 if (value->IsUndefined() || is_const_property) {
1182 // Lookup the property in the global object, and don't set the
1183 // value of the variable if the property is already there.
1184 LookupResult lookup;
1185 global->Lookup(*name, &lookup);
1186 if (lookup.IsProperty()) {
1187 // Determine if the property is local by comparing the holder
1188 // against the global object. The information will be used to
1189 // avoid throwing re-declaration errors when declaring
1190 // variables or constants that exist in the prototype chain.
1191 bool is_local = (*global == lookup.holder());
1192 // Get the property attributes and determine if the property is
1193 // read-only.
1194 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1195 bool is_read_only = (attributes & READ_ONLY) != 0;
1196 if (lookup.type() == INTERCEPTOR) {
1197 // If the interceptor says the property is there, we
1198 // just return undefined without overwriting the property.
1199 // Otherwise, we continue to setting the property.
1200 if (attributes != ABSENT) {
1201 // Check if the existing property conflicts with regards to const.
1202 if (is_local && (is_read_only || is_const_property)) {
1203 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001204 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205 };
1206 // The property already exists without conflicting: Go to
1207 // the next declaration.
1208 continue;
1209 }
1210 // Fall-through and introduce the absent property by using
1211 // SetProperty.
1212 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001213 // For const properties, we treat a callback with this name
1214 // even in the prototype as a conflicting declaration.
1215 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001216 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001217 }
1218 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001219 if (is_local && (is_read_only || is_const_property)) {
1220 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001221 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001222 }
1223 // The property already exists without conflicting: Go to
1224 // the next declaration.
1225 continue;
1226 }
1227 }
1228 } else {
1229 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001230 Handle<SharedFunctionInfo> shared =
1231 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001232 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001233 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1234 context,
1235 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001236 value = function;
1237 }
1238
1239 LookupResult lookup;
1240 global->LocalLookup(*name, &lookup);
1241
1242 PropertyAttributes attributes = is_const_property
1243 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1244 : base;
1245
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001246 // There's a local property that we need to overwrite because
1247 // we're either declaring a function or there's an interceptor
1248 // that claims the property is absent.
1249 //
1250 // Check for conflicting re-declarations. We cannot have
1251 // conflicting types in case of intercepted properties because
1252 // they are absent.
1253 if (lookup.IsProperty() &&
1254 (lookup.type() != INTERCEPTOR) &&
1255 (lookup.IsReadOnly() || is_const_property)) {
1256 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001257 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001258 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001259
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001260 // Safari does not allow the invocation of callback setters for
1261 // function declarations. To mimic this behavior, we do not allow
1262 // the invocation of setters for function values. This makes a
1263 // difference for global functions with the same names as event
1264 // handlers such as "function onload() {}". Firefox does call the
1265 // onload setter in those case and Safari does not. We follow
1266 // Safari for compatibility.
1267 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001268 // Do not change DONT_DELETE to false from true.
1269 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1270 attributes = static_cast<PropertyAttributes>(
1271 attributes | (lookup.GetAttributes() & DONT_DELETE));
1272 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001273 RETURN_IF_EMPTY_HANDLE(isolate,
1274 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001275 name,
1276 value,
1277 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001279 RETURN_IF_EMPTY_HANDLE(isolate,
1280 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001281 name,
1282 value,
1283 attributes,
1284 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001285 }
1286 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001287
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001288 ASSERT(!isolate->has_pending_exception());
1289 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001290}
1291
1292
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001293RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001294 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001295 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001296
ager@chromium.org7c537e22008-10-16 08:43:32 +00001297 CONVERT_ARG_CHECKED(Context, context, 0);
1298 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001299 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001300 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001301 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001302
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001303 // Declarations are always done in a function or global context.
1304 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305
1306 int index;
1307 PropertyAttributes attributes;
1308 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001309 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001310 context->Lookup(name, flags, &index, &attributes);
1311
1312 if (attributes != ABSENT) {
1313 // The name was declared before; check for conflicting
1314 // re-declarations: This is similar to the code in parser.cc in
1315 // the AstBuildingParser::Declare function.
1316 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1317 // Functions are not read-only.
1318 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1319 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001320 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001321 }
1322
1323 // Initialize it if necessary.
1324 if (*initial_value != NULL) {
1325 if (index >= 0) {
1326 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001327 // the function context or the arguments object.
1328 if (holder->IsContext()) {
1329 ASSERT(holder.is_identical_to(context));
1330 if (((attributes & READ_ONLY) == 0) ||
1331 context->get(index)->IsTheHole()) {
1332 context->set(index, *initial_value);
1333 }
1334 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001335 // The holder is an arguments object.
1336 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001337 Handle<Object> result = SetElement(arguments, index, initial_value,
1338 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001339 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001340 }
1341 } else {
1342 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001343 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001344 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001345 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001346 SetProperty(context_ext, name, initial_value,
1347 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001348 }
1349 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001350
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001351 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001352 // The property is not in the function context. It needs to be
1353 // "declared" in the function context's extension context, or in the
1354 // global context.
1355 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001356 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001357 // The function context's extension context exists - use it.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001358 context_ext = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001359 } else {
1360 // The function context's extension context does not exists - allocate
1361 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001362 context_ext = isolate->factory()->NewJSObject(
1363 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001364 // And store it in the extension slot.
1365 context->set_extension(*context_ext);
1366 }
1367 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001368
ager@chromium.org7c537e22008-10-16 08:43:32 +00001369 // Declare the property by setting it to the initial value if provided,
1370 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1371 // constant declarations).
1372 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001373 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001374 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001375 // Declaring a const context slot is a conflicting declaration if
1376 // there is a callback with that name in a prototype. It is
1377 // allowed to introduce const variables in
1378 // JSContextExtensionObjects. They are treated specially in
1379 // SetProperty and no setters are invoked for those since they are
1380 // not real JSObjects.
1381 if (initial_value->IsTheHole() &&
1382 !context_ext->IsJSContextExtensionObject()) {
1383 LookupResult lookup;
1384 context_ext->Lookup(*name, &lookup);
1385 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001386 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001387 }
1388 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001389 RETURN_IF_EMPTY_HANDLE(isolate,
1390 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001391 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001392 }
1393
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001394 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001395}
1396
1397
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001398RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001400 // args[0] == name
1401 // args[1] == strict_mode
1402 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001403
1404 // Determine if we need to assign to the variable if it already
1405 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001406 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1407 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001408
1409 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001410 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001411 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001412 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001413 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001414
1415 // According to ECMA-262, section 12.2, page 62, the property must
1416 // not be deletable.
1417 PropertyAttributes attributes = DONT_DELETE;
1418
1419 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001420 // there, there is a property with this name in the prototype chain.
1421 // We follow Safari and Firefox behavior and only set the property
1422 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001423 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001424 // Note that objects can have hidden prototypes, so we need to traverse
1425 // the whole chain of hidden prototypes to do a 'local' lookup.
1426 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001427 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001428 while (true) {
1429 real_holder->LocalLookup(*name, &lookup);
1430 if (lookup.IsProperty()) {
1431 // Determine if this is a redeclaration of something read-only.
1432 if (lookup.IsReadOnly()) {
1433 // If we found readonly property on one of hidden prototypes,
1434 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001435 if (real_holder != isolate->context()->global()) break;
1436 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001437 }
1438
1439 // Determine if this is a redeclaration of an intercepted read-only
1440 // property and figure out if the property exists at all.
1441 bool found = true;
1442 PropertyType type = lookup.type();
1443 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001444 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001445 Handle<JSObject> holder(real_holder);
1446 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1447 real_holder = *holder;
1448 if (intercepted == ABSENT) {
1449 // The interceptor claims the property isn't there. We need to
1450 // make sure to introduce it.
1451 found = false;
1452 } else if ((intercepted & READ_ONLY) != 0) {
1453 // The property is present, but read-only. Since we're trying to
1454 // overwrite it with a variable declaration we must throw a
1455 // re-declaration error. However if we found readonly property
1456 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001457 if (real_holder != isolate->context()->global()) break;
1458 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001459 }
1460 }
1461
1462 if (found && !assign) {
1463 // The global property is there and we're not assigning any value
1464 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001465 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001466 }
1467
1468 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001469 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001470 return real_holder->SetProperty(
1471 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001472 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001473
1474 Object* proto = real_holder->GetPrototype();
1475 if (!proto->IsJSObject())
1476 break;
1477
1478 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1479 break;
1480
1481 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001482 }
1483
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001484 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001485 if (assign) {
1486 return global->SetProperty(*name, args[2], attributes, strict_mode);
1487 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001488 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001489}
1490
1491
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001492RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001493 // All constants are declared with an initial value. The name
1494 // of the constant is the first argument and the initial value
1495 // is the second.
1496 RUNTIME_ASSERT(args.length() == 2);
1497 CONVERT_ARG_CHECKED(String, name, 0);
1498 Handle<Object> value = args.at<Object>(1);
1499
1500 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001501 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001502
1503 // According to ECMA-262, section 12.2, page 62, the property must
1504 // not be deletable. Since it's a const, it must be READ_ONLY too.
1505 PropertyAttributes attributes =
1506 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1507
1508 // Lookup the property locally in the global object. If it isn't
1509 // there, we add the property and take special precautions to always
1510 // add it as a local property even in case of callbacks in the
1511 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001512 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001513 LookupResult lookup;
1514 global->LocalLookup(*name, &lookup);
1515 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001516 return global->SetLocalPropertyIgnoreAttributes(*name,
1517 *value,
1518 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001519 }
1520
1521 // Determine if this is a redeclaration of something not
1522 // read-only. In case the result is hidden behind an interceptor we
1523 // need to ask it for the property attributes.
1524 if (!lookup.IsReadOnly()) {
1525 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001526 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001527 }
1528
1529 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1530
1531 // Throw re-declaration error if the intercepted property is present
1532 // but not read-only.
1533 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001534 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001535 }
1536
1537 // Restore global object from context (in case of GC) and continue
1538 // with setting the value because the property is either absent or
1539 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001540 HandleScope handle_scope(isolate);
1541 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001542
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001543 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001544 // property through an interceptor and only do it if it's
1545 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001546 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001547 RETURN_IF_EMPTY_HANDLE(isolate,
1548 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001549 name,
1550 value,
1551 attributes,
1552 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001553 return *value;
1554 }
1555
1556 // Set the value, but only we're assigning the initial value to a
1557 // constant. For now, we determine this by checking if the
1558 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001559 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560 PropertyType type = lookup.type();
1561 if (type == FIELD) {
1562 FixedArray* properties = global->properties();
1563 int index = lookup.GetFieldIndex();
1564 if (properties->get(index)->IsTheHole()) {
1565 properties->set(index, *value);
1566 }
1567 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001568 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1569 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001570 }
1571 } else {
1572 // Ignore re-initialization of constants that have already been
1573 // assigned a function value.
1574 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1575 }
1576
1577 // Use the set value as the result of the operation.
1578 return *value;
1579}
1580
1581
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001582RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001583 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001584 ASSERT(args.length() == 3);
1585
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001586 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001587 ASSERT(!value->IsTheHole());
1588 CONVERT_ARG_CHECKED(Context, context, 1);
1589 Handle<String> name(String::cast(args[2]));
1590
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001591 // Initializations are always done in a function or global context.
1592 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001593
1594 int index;
1595 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001596 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001597 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001598 context->Lookup(name, flags, &index, &attributes);
1599
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001600 // In most situations, the property introduced by the const
1601 // declaration should be present in the context extension object.
1602 // However, because declaration and initialization are separate, the
1603 // property might have been deleted (if it was introduced by eval)
1604 // before we reach the initialization point.
1605 //
1606 // Example:
1607 //
1608 // function f() { eval("delete x; const x;"); }
1609 //
1610 // In that case, the initialization behaves like a normal assignment
1611 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001612 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001613 if (holder->IsContext()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001614 // Property was found in a context. Perform the assignment if we
1615 // found some non-constant or an uninitialized constant.
1616 Handle<Context> context = Handle<Context>::cast(holder);
1617 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1618 context->set(index, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001619 }
1620 } else {
1621 // The holder is an arguments object.
1622 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001623 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001624 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001625 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001626 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001627 }
1628 return *value;
1629 }
1630
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001631 // The property could not be found, we introduce it in the global
1632 // context.
1633 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001634 Handle<JSObject> global = Handle<JSObject>(
1635 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001636 // Strict mode not needed (const disallowed in strict mode).
1637 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001638 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001639 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001640 return *value;
1641 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001642
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001643 // The property was present in a context extension object.
1644 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001645
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001646 if (*context_ext == context->extension()) {
1647 // This is the property that was introduced by the const
1648 // declaration. Set it if it hasn't been set before. NOTE: We
1649 // cannot use GetProperty() to get the current value as it
1650 // 'unholes' the value.
1651 LookupResult lookup;
1652 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1653 ASSERT(lookup.IsProperty()); // the property was declared
1654 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1655
1656 PropertyType type = lookup.type();
1657 if (type == FIELD) {
1658 FixedArray* properties = context_ext->properties();
1659 int index = lookup.GetFieldIndex();
1660 if (properties->get(index)->IsTheHole()) {
1661 properties->set(index, *value);
1662 }
1663 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001664 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1665 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001666 }
1667 } else {
1668 // We should not reach here. Any real, named property should be
1669 // either a field or a dictionary slot.
1670 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001671 }
1672 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001673 // The property was found in a different context extension object.
1674 // Set it if it is not a read-only property.
1675 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001676 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001677 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001678 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001679 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001680 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001681 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001682
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001683 return *value;
1684}
1685
1686
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001687RUNTIME_FUNCTION(MaybeObject*,
1688 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001689 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001690 ASSERT(args.length() == 2);
1691 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001692 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001693 if (object->HasFastProperties()) {
1694 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1695 }
1696 return *object;
1697}
1698
1699
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001700RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001701 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001702 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001703 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1704 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001705 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001706 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001707 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001708 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001709 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001710 RUNTIME_ASSERT(index >= 0);
1711 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001712 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001713 Handle<Object> result = RegExpImpl::Exec(regexp,
1714 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001715 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001716 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001717 if (result.is_null()) return Failure::Exception();
1718 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001719}
1720
1721
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001722RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001723 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001724 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001725 if (elements_count < 0 ||
1726 elements_count > FixedArray::kMaxLength ||
1727 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001728 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001729 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001730 Object* new_object;
1731 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001732 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001733 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1734 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001735 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001736 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1737 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001738 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1739 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001740 {
1741 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001742 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001743 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001744 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001745 }
1746 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001747 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001748 array->set_elements(elements);
1749 array->set_length(Smi::FromInt(elements_count));
1750 // Write in-object properties after the length of the array.
1751 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1752 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1753 return array;
1754}
1755
1756
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001757RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001758 AssertNoAllocation no_alloc;
1759 ASSERT(args.length() == 5);
1760 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1761 CONVERT_CHECKED(String, source, args[1]);
1762
1763 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001764 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001765
1766 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001767 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001768
1769 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001770 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001771
1772 Map* map = regexp->map();
1773 Object* constructor = map->constructor();
1774 if (constructor->IsJSFunction() &&
1775 JSFunction::cast(constructor)->initial_map() == map) {
1776 // If we still have the original map, set in-object properties directly.
1777 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1778 // TODO(lrn): Consider skipping write barrier on booleans as well.
1779 // Both true and false should be in oldspace at all times.
1780 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1781 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1782 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1783 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1784 Smi::FromInt(0),
1785 SKIP_WRITE_BARRIER);
1786 return regexp;
1787 }
1788
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001789 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001790 PropertyAttributes final =
1791 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1792 PropertyAttributes writable =
1793 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001794 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001795 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001796 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001797 source,
1798 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001799 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001800 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001801 global,
1802 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001803 ASSERT(!result->IsFailure());
1804 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001805 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001806 ignoreCase,
1807 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001808 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001809 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001810 multiline,
1811 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001812 ASSERT(!result->IsFailure());
1813 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001814 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001815 Smi::FromInt(0),
1816 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001817 ASSERT(!result->IsFailure());
1818 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001819 return regexp;
1820}
1821
1822
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001823RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001824 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001825 ASSERT(args.length() == 1);
1826 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1827 // This is necessary to enable fast checks for absence of elements
1828 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001829 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001830 return Smi::FromInt(0);
1831}
1832
1833
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001834static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1835 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001836 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001837 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001838 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1839 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1840 Handle<JSFunction> optimized =
1841 isolate->factory()->NewFunction(key,
1842 JS_OBJECT_TYPE,
1843 JSObject::kHeaderSize,
1844 code,
1845 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001846 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001847 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001848 return optimized;
1849}
1850
1851
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001852RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001853 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001854 ASSERT(args.length() == 1);
1855 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1856
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001857 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1858 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1859 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1860 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1861 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1862 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1863 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001864
1865 return *holder;
1866}
1867
1868
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001869RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
1870 NoHandleAllocation handle_free;
1871 ASSERT(args.length() == 1);
1872 CONVERT_CHECKED(JSFunction, function, args[0]);
1873 SharedFunctionInfo* shared = function->shared();
1874 if (shared->native() || shared->strict_mode()) {
1875 return isolate->heap()->undefined_value();
1876 }
1877 // Returns undefined for strict or native functions, or
1878 // the associated global receiver for "normal" functions.
1879
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001880 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001881 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001882 return global_context->global()->global_receiver();
1883}
1884
1885
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001886RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001887 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001888 ASSERT(args.length() == 4);
1889 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001890 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001891 Handle<String> pattern = args.at<String>(2);
1892 Handle<String> flags = args.at<String>(3);
1893
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001894 // Get the RegExp function from the context in the literals array.
1895 // This is the RegExp function from the context in which the
1896 // function was created. We do not use the RegExp function from the
1897 // current global context because this might be the RegExp function
1898 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001899 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001900 Handle<JSFunction>(
1901 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001902 // Compute the regular expression literal.
1903 bool has_pending_exception;
1904 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001905 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1906 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001907 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001908 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001909 return Failure::Exception();
1910 }
1911 literals->set(index, *regexp);
1912 return *regexp;
1913}
1914
1915
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001916RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001917 NoHandleAllocation ha;
1918 ASSERT(args.length() == 1);
1919
1920 CONVERT_CHECKED(JSFunction, f, args[0]);
1921 return f->shared()->name();
1922}
1923
1924
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001925RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001926 NoHandleAllocation ha;
1927 ASSERT(args.length() == 2);
1928
1929 CONVERT_CHECKED(JSFunction, f, args[0]);
1930 CONVERT_CHECKED(String, name, args[1]);
1931 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001932 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001933}
1934
1935
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001936RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1937 NoHandleAllocation ha;
1938 ASSERT(args.length() == 1);
1939 CONVERT_CHECKED(JSFunction, f, args[0]);
1940 return isolate->heap()->ToBoolean(
1941 f->shared()->name_should_print_as_anonymous());
1942}
1943
1944
1945RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1946 NoHandleAllocation ha;
1947 ASSERT(args.length() == 1);
1948 CONVERT_CHECKED(JSFunction, f, args[0]);
1949 f->shared()->set_name_should_print_as_anonymous(true);
1950 return isolate->heap()->undefined_value();
1951}
1952
1953
whesse@chromium.org7b260152011-06-20 15:33:18 +00001954RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1955 HandleScope scope(isolate);
1956 ASSERT(args.length() == 1);
1957
1958 CONVERT_CHECKED(JSFunction, fun, args[0]);
1959 fun->shared()->set_bound(true);
1960 return isolate->heap()->undefined_value();
1961}
1962
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001963RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001964 NoHandleAllocation ha;
1965 ASSERT(args.length() == 1);
1966
1967 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001968 Object* obj = f->RemovePrototype();
1969 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001970
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001971 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001972}
1973
1974
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001975RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001976 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001977 ASSERT(args.length() == 1);
1978
1979 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001980 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1981 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001982
1983 return *GetScriptWrapper(Handle<Script>::cast(script));
1984}
1985
1986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001987RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001988 NoHandleAllocation ha;
1989 ASSERT(args.length() == 1);
1990
1991 CONVERT_CHECKED(JSFunction, f, args[0]);
1992 return f->shared()->GetSourceCode();
1993}
1994
1995
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001996RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001997 NoHandleAllocation ha;
1998 ASSERT(args.length() == 1);
1999
2000 CONVERT_CHECKED(JSFunction, fun, args[0]);
2001 int pos = fun->shared()->start_position();
2002 return Smi::FromInt(pos);
2003}
2004
2005
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002006RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002007 ASSERT(args.length() == 2);
2008
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002009 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002010 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2011
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002012 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2013
2014 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002015 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002016}
2017
2018
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002019RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002020 NoHandleAllocation ha;
2021 ASSERT(args.length() == 2);
2022
2023 CONVERT_CHECKED(JSFunction, fun, args[0]);
2024 CONVERT_CHECKED(String, name, args[1]);
2025 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002026 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002027}
2028
2029
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002030RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002031 NoHandleAllocation ha;
2032 ASSERT(args.length() == 2);
2033
2034 CONVERT_CHECKED(JSFunction, fun, args[0]);
2035 CONVERT_CHECKED(Smi, length, args[1]);
2036 fun->shared()->set_length(length->value());
2037 return length;
2038}
2039
2040
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002041// Creates a local, readonly, property called length with the correct
2042// length (when read by the user). This effectively overwrites the
2043// interceptor used to normally provide the length.
2044RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionSetLength) {
2045 NoHandleAllocation ha;
2046 ASSERT(args.length() == 2);
2047 CONVERT_CHECKED(JSFunction, fun, args[0]);
2048 CONVERT_CHECKED(Smi, length, args[1]);
2049 MaybeObject* maybe_name =
2050 isolate->heap()->AllocateStringFromAscii(CStrVector("length"));
2051 String* name;
2052 if (!maybe_name->To(&name)) return maybe_name;
2053 PropertyAttributes attr =
2054 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
2055 return fun->AddProperty(name, length, attr, kNonStrictMode);
2056}
2057
2058
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002059RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002060 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002061 ASSERT(args.length() == 2);
2062
2063 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002064 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002065 Object* obj;
2066 { MaybeObject* maybe_obj =
2067 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2068 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2069 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002070 return args[0]; // return TOS
2071}
2072
2073
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002074RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2075 NoHandleAllocation ha;
2076 RUNTIME_ASSERT(args.length() == 1);
2077 CONVERT_CHECKED(JSFunction, function, args[0]);
2078
2079 MaybeObject* maybe_name =
2080 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2081 String* name;
2082 if (!maybe_name->To(&name)) return maybe_name;
2083
2084 if (function->HasFastProperties()) {
2085 // Construct a new field descriptor with updated attributes.
2086 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2087 int index = instance_desc->Search(name);
2088 ASSERT(index != DescriptorArray::kNotFound);
2089 PropertyDetails details(instance_desc->GetDetails(index));
2090 CallbacksDescriptor new_desc(name,
2091 instance_desc->GetValue(index),
2092 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2093 details.index());
2094 // Construct a new field descriptors array containing the new descriptor.
2095 Object* descriptors_unchecked;
2096 { MaybeObject* maybe_descriptors_unchecked =
2097 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2098 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2099 return maybe_descriptors_unchecked;
2100 }
2101 }
2102 DescriptorArray* new_descriptors =
2103 DescriptorArray::cast(descriptors_unchecked);
2104 // Create a new map featuring the new field descriptors array.
2105 Object* map_unchecked;
2106 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2107 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2108 return maybe_map_unchecked;
2109 }
2110 }
2111 Map* new_map = Map::cast(map_unchecked);
2112 new_map->set_instance_descriptors(new_descriptors);
2113 function->set_map(new_map);
2114 } else { // Dictionary properties.
2115 // Directly manipulate the property details.
2116 int entry = function->property_dictionary()->FindEntry(name);
2117 ASSERT(entry != StringDictionary::kNotFound);
2118 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2119 PropertyDetails new_details(
2120 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2121 details.type(),
2122 details.index());
2123 function->property_dictionary()->DetailsAtPut(entry, new_details);
2124 }
2125 return function;
2126}
2127
2128
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002129RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002130 NoHandleAllocation ha;
2131 ASSERT(args.length() == 1);
2132
2133 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002134 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002135}
2136
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002137
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002138RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002139 NoHandleAllocation ha;
2140 ASSERT(args.length() == 1);
2141
2142 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002143 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002144}
2145
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002146
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002147RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002148 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002149 ASSERT(args.length() == 2);
2150
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002151 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002152 Handle<Object> code = args.at<Object>(1);
2153
2154 Handle<Context> context(target->context());
2155
2156 if (!code->IsNull()) {
2157 RUNTIME_ASSERT(code->IsJSFunction());
2158 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002159 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002160
2161 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002162 return Failure::Exception();
2163 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002164 // Since we don't store the source for this we should never
2165 // optimize this.
2166 shared->code()->set_optimizable(false);
2167
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002168 // Set the code, scope info, formal parameter count,
2169 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002170 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002171 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002172 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002173 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002174 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002175 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002176 // Set the source code of the target function to undefined.
2177 // SetCode is only used for built-in constructors like String,
2178 // Array, and Object, and some web code
2179 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002180 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002181 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002182 // Clear the optimization hints related to the compiled code as these are no
2183 // longer valid when the code is overwritten.
2184 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002185 context = Handle<Context>(fun->context());
2186
2187 // Make sure we get a fresh copy of the literal vector to avoid
2188 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002189 int number_of_literals = fun->NumberOfLiterals();
2190 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002191 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002192 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002193 // Insert the object, regexp and array functions in the literals
2194 // array prefix. These are the functions that will be used when
2195 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002196 literals->set(JSFunction::kLiteralGlobalContextIndex,
2197 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002198 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002199 // It's okay to skip the write barrier here because the literals
2200 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002201 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002202 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002203 }
2204
2205 target->set_context(*context);
2206 return *target;
2207}
2208
2209
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002210RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002211 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002212 ASSERT(args.length() == 2);
2213 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002214 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002215 RUNTIME_ASSERT(num >= 0);
2216 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002217 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002218}
2219
2220
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002221MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2222 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002223 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002224 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002225 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002226 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002227 }
2228 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002229 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002230}
2231
2232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002233RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002234 NoHandleAllocation ha;
2235 ASSERT(args.length() == 2);
2236
2237 CONVERT_CHECKED(String, subject, args[0]);
2238 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002239 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002240
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002241 uint32_t i = 0;
2242 if (index->IsSmi()) {
2243 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002244 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002245 i = value;
2246 } else {
2247 ASSERT(index->IsHeapNumber());
2248 double value = HeapNumber::cast(index)->value();
2249 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002250 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002251
2252 // Flatten the string. If someone wants to get a char at an index
2253 // in a cons string, it is likely that more indices will be
2254 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002255 Object* flat;
2256 { MaybeObject* maybe_flat = subject->TryFlatten();
2257 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2258 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002259 subject = String::cast(flat);
2260
2261 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002262 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002263 }
2264
2265 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002266}
2267
2268
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002269RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002270 NoHandleAllocation ha;
2271 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002272 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002273}
2274
lrn@chromium.org25156de2010-04-06 13:10:27 +00002275
2276class FixedArrayBuilder {
2277 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002278 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2279 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002280 length_(0) {
2281 // Require a non-zero initial size. Ensures that doubling the size to
2282 // extend the array will work.
2283 ASSERT(initial_capacity > 0);
2284 }
2285
2286 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2287 : array_(backing_store),
2288 length_(0) {
2289 // Require a non-zero initial size. Ensures that doubling the size to
2290 // extend the array will work.
2291 ASSERT(backing_store->length() > 0);
2292 }
2293
2294 bool HasCapacity(int elements) {
2295 int length = array_->length();
2296 int required_length = length_ + elements;
2297 return (length >= required_length);
2298 }
2299
2300 void EnsureCapacity(int elements) {
2301 int length = array_->length();
2302 int required_length = length_ + elements;
2303 if (length < required_length) {
2304 int new_length = length;
2305 do {
2306 new_length *= 2;
2307 } while (new_length < required_length);
2308 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002309 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002310 array_->CopyTo(0, *extended_array, 0, length_);
2311 array_ = extended_array;
2312 }
2313 }
2314
2315 void Add(Object* value) {
2316 ASSERT(length_ < capacity());
2317 array_->set(length_, value);
2318 length_++;
2319 }
2320
2321 void Add(Smi* value) {
2322 ASSERT(length_ < capacity());
2323 array_->set(length_, value);
2324 length_++;
2325 }
2326
2327 Handle<FixedArray> array() {
2328 return array_;
2329 }
2330
2331 int length() {
2332 return length_;
2333 }
2334
2335 int capacity() {
2336 return array_->length();
2337 }
2338
2339 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002340 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002341 result_array->set_length(Smi::FromInt(length_));
2342 return result_array;
2343 }
2344
2345 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2346 target_array->set_elements(*array_);
2347 target_array->set_length(Smi::FromInt(length_));
2348 return target_array;
2349 }
2350
2351 private:
2352 Handle<FixedArray> array_;
2353 int length_;
2354};
2355
2356
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002357// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002358const int kStringBuilderConcatHelperLengthBits = 11;
2359const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002360
2361template <typename schar>
2362static inline void StringBuilderConcatHelper(String*,
2363 schar*,
2364 FixedArray*,
2365 int);
2366
lrn@chromium.org25156de2010-04-06 13:10:27 +00002367typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2368 StringBuilderSubstringLength;
2369typedef BitField<int,
2370 kStringBuilderConcatHelperLengthBits,
2371 kStringBuilderConcatHelperPositionBits>
2372 StringBuilderSubstringPosition;
2373
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002374
2375class ReplacementStringBuilder {
2376 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002377 ReplacementStringBuilder(Heap* heap,
2378 Handle<String> subject,
2379 int estimated_part_count)
2380 : heap_(heap),
2381 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002382 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002383 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002384 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002385 // Require a non-zero initial size. Ensures that doubling the size to
2386 // extend the array will work.
2387 ASSERT(estimated_part_count > 0);
2388 }
2389
lrn@chromium.org25156de2010-04-06 13:10:27 +00002390 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2391 int from,
2392 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002393 ASSERT(from >= 0);
2394 int length = to - from;
2395 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002396 if (StringBuilderSubstringLength::is_valid(length) &&
2397 StringBuilderSubstringPosition::is_valid(from)) {
2398 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2399 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002400 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002401 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002402 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002403 builder->Add(Smi::FromInt(-length));
2404 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002405 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002406 }
2407
2408
2409 void EnsureCapacity(int elements) {
2410 array_builder_.EnsureCapacity(elements);
2411 }
2412
2413
2414 void AddSubjectSlice(int from, int to) {
2415 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002416 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002417 }
2418
2419
2420 void AddString(Handle<String> string) {
2421 int length = string->length();
2422 ASSERT(length > 0);
2423 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002424 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002425 is_ascii_ = false;
2426 }
2427 IncrementCharacterCount(length);
2428 }
2429
2430
2431 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002432 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002433 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002434 }
2435
2436 Handle<String> joined_string;
2437 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002438 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002439 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002440 char* char_buffer = seq->GetChars();
2441 StringBuilderConcatHelper(*subject_,
2442 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002443 *array_builder_.array(),
2444 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002445 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002446 } else {
2447 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002448 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002449 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002450 uc16* char_buffer = seq->GetChars();
2451 StringBuilderConcatHelper(*subject_,
2452 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002453 *array_builder_.array(),
2454 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002455 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002456 }
2457 return joined_string;
2458 }
2459
2460
2461 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002462 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002463 V8::FatalProcessOutOfMemory("String.replace result too large.");
2464 }
2465 character_count_ += by;
2466 }
2467
lrn@chromium.org25156de2010-04-06 13:10:27 +00002468 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002469 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002470 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002471
lrn@chromium.org25156de2010-04-06 13:10:27 +00002472 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002473 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2474 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002475 }
2476
2477
ager@chromium.org04921a82011-06-27 13:21:41 +00002478 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2479 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002480 }
2481
2482
2483 void AddElement(Object* element) {
2484 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002485 ASSERT(array_builder_.capacity() > array_builder_.length());
2486 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002487 }
2488
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002489 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002490 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002491 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002492 int character_count_;
2493 bool is_ascii_;
2494};
2495
2496
2497class CompiledReplacement {
2498 public:
2499 CompiledReplacement()
2500 : parts_(1), replacement_substrings_(0) {}
2501
2502 void Compile(Handle<String> replacement,
2503 int capture_count,
2504 int subject_length);
2505
2506 void Apply(ReplacementStringBuilder* builder,
2507 int match_from,
2508 int match_to,
2509 Handle<JSArray> last_match_info);
2510
2511 // Number of distinct parts of the replacement pattern.
2512 int parts() {
2513 return parts_.length();
2514 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002515
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002516 private:
2517 enum PartType {
2518 SUBJECT_PREFIX = 1,
2519 SUBJECT_SUFFIX,
2520 SUBJECT_CAPTURE,
2521 REPLACEMENT_SUBSTRING,
2522 REPLACEMENT_STRING,
2523
2524 NUMBER_OF_PART_TYPES
2525 };
2526
2527 struct ReplacementPart {
2528 static inline ReplacementPart SubjectMatch() {
2529 return ReplacementPart(SUBJECT_CAPTURE, 0);
2530 }
2531 static inline ReplacementPart SubjectCapture(int capture_index) {
2532 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2533 }
2534 static inline ReplacementPart SubjectPrefix() {
2535 return ReplacementPart(SUBJECT_PREFIX, 0);
2536 }
2537 static inline ReplacementPart SubjectSuffix(int subject_length) {
2538 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2539 }
2540 static inline ReplacementPart ReplacementString() {
2541 return ReplacementPart(REPLACEMENT_STRING, 0);
2542 }
2543 static inline ReplacementPart ReplacementSubString(int from, int to) {
2544 ASSERT(from >= 0);
2545 ASSERT(to > from);
2546 return ReplacementPart(-from, to);
2547 }
2548
2549 // If tag <= 0 then it is the negation of a start index of a substring of
2550 // the replacement pattern, otherwise it's a value from PartType.
2551 ReplacementPart(int tag, int data)
2552 : tag(tag), data(data) {
2553 // Must be non-positive or a PartType value.
2554 ASSERT(tag < NUMBER_OF_PART_TYPES);
2555 }
2556 // Either a value of PartType or a non-positive number that is
2557 // the negation of an index into the replacement string.
2558 int tag;
2559 // The data value's interpretation depends on the value of tag:
2560 // tag == SUBJECT_PREFIX ||
2561 // tag == SUBJECT_SUFFIX: data is unused.
2562 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2563 // tag == REPLACEMENT_SUBSTRING ||
2564 // tag == REPLACEMENT_STRING: data is index into array of substrings
2565 // of the replacement string.
2566 // tag <= 0: Temporary representation of the substring of the replacement
2567 // string ranging over -tag .. data.
2568 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2569 // substring objects.
2570 int data;
2571 };
2572
2573 template<typename Char>
2574 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2575 Vector<Char> characters,
2576 int capture_count,
2577 int subject_length) {
2578 int length = characters.length();
2579 int last = 0;
2580 for (int i = 0; i < length; i++) {
2581 Char c = characters[i];
2582 if (c == '$') {
2583 int next_index = i + 1;
2584 if (next_index == length) { // No next character!
2585 break;
2586 }
2587 Char c2 = characters[next_index];
2588 switch (c2) {
2589 case '$':
2590 if (i > last) {
2591 // There is a substring before. Include the first "$".
2592 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2593 last = next_index + 1; // Continue after the second "$".
2594 } else {
2595 // Let the next substring start with the second "$".
2596 last = next_index;
2597 }
2598 i = next_index;
2599 break;
2600 case '`':
2601 if (i > last) {
2602 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2603 }
2604 parts->Add(ReplacementPart::SubjectPrefix());
2605 i = next_index;
2606 last = i + 1;
2607 break;
2608 case '\'':
2609 if (i > last) {
2610 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2611 }
2612 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2613 i = next_index;
2614 last = i + 1;
2615 break;
2616 case '&':
2617 if (i > last) {
2618 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2619 }
2620 parts->Add(ReplacementPart::SubjectMatch());
2621 i = next_index;
2622 last = i + 1;
2623 break;
2624 case '0':
2625 case '1':
2626 case '2':
2627 case '3':
2628 case '4':
2629 case '5':
2630 case '6':
2631 case '7':
2632 case '8':
2633 case '9': {
2634 int capture_ref = c2 - '0';
2635 if (capture_ref > capture_count) {
2636 i = next_index;
2637 continue;
2638 }
2639 int second_digit_index = next_index + 1;
2640 if (second_digit_index < length) {
2641 // Peek ahead to see if we have two digits.
2642 Char c3 = characters[second_digit_index];
2643 if ('0' <= c3 && c3 <= '9') { // Double digits.
2644 int double_digit_ref = capture_ref * 10 + c3 - '0';
2645 if (double_digit_ref <= capture_count) {
2646 next_index = second_digit_index;
2647 capture_ref = double_digit_ref;
2648 }
2649 }
2650 }
2651 if (capture_ref > 0) {
2652 if (i > last) {
2653 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2654 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002655 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002656 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2657 last = next_index + 1;
2658 }
2659 i = next_index;
2660 break;
2661 }
2662 default:
2663 i = next_index;
2664 break;
2665 }
2666 }
2667 }
2668 if (length > last) {
2669 if (last == 0) {
2670 parts->Add(ReplacementPart::ReplacementString());
2671 } else {
2672 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2673 }
2674 }
2675 }
2676
2677 ZoneList<ReplacementPart> parts_;
2678 ZoneList<Handle<String> > replacement_substrings_;
2679};
2680
2681
2682void CompiledReplacement::Compile(Handle<String> replacement,
2683 int capture_count,
2684 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002685 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002686 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002687 String::FlatContent content = replacement->GetFlatContent();
2688 ASSERT(content.IsFlat());
2689 if (content.IsAscii()) {
2690 ParseReplacementPattern(&parts_,
2691 content.ToAsciiVector(),
2692 capture_count,
2693 subject_length);
2694 } else {
2695 ASSERT(content.IsTwoByte());
2696 ParseReplacementPattern(&parts_,
2697 content.ToUC16Vector(),
2698 capture_count,
2699 subject_length);
2700 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002701 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002702 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002703 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002704 int substring_index = 0;
2705 for (int i = 0, n = parts_.length(); i < n; i++) {
2706 int tag = parts_[i].tag;
2707 if (tag <= 0) { // A replacement string slice.
2708 int from = -tag;
2709 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002710 replacement_substrings_.Add(
2711 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002712 parts_[i].tag = REPLACEMENT_SUBSTRING;
2713 parts_[i].data = substring_index;
2714 substring_index++;
2715 } else if (tag == REPLACEMENT_STRING) {
2716 replacement_substrings_.Add(replacement);
2717 parts_[i].data = substring_index;
2718 substring_index++;
2719 }
2720 }
2721}
2722
2723
2724void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2725 int match_from,
2726 int match_to,
2727 Handle<JSArray> last_match_info) {
2728 for (int i = 0, n = parts_.length(); i < n; i++) {
2729 ReplacementPart part = parts_[i];
2730 switch (part.tag) {
2731 case SUBJECT_PREFIX:
2732 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2733 break;
2734 case SUBJECT_SUFFIX: {
2735 int subject_length = part.data;
2736 if (match_to < subject_length) {
2737 builder->AddSubjectSlice(match_to, subject_length);
2738 }
2739 break;
2740 }
2741 case SUBJECT_CAPTURE: {
2742 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002743 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002744 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2745 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2746 if (from >= 0 && to > from) {
2747 builder->AddSubjectSlice(from, to);
2748 }
2749 break;
2750 }
2751 case REPLACEMENT_SUBSTRING:
2752 case REPLACEMENT_STRING:
2753 builder->AddString(replacement_substrings_[part.data]);
2754 break;
2755 default:
2756 UNREACHABLE();
2757 }
2758 }
2759}
2760
2761
2762
lrn@chromium.org303ada72010-10-27 09:33:13 +00002763MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002764 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002765 String* subject,
2766 JSRegExp* regexp,
2767 String* replacement,
2768 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002769 ASSERT(subject->IsFlat());
2770 ASSERT(replacement->IsFlat());
2771
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002772 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002773
2774 int length = subject->length();
2775 Handle<String> subject_handle(subject);
2776 Handle<JSRegExp> regexp_handle(regexp);
2777 Handle<String> replacement_handle(replacement);
2778 Handle<JSArray> last_match_info_handle(last_match_info);
2779 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2780 subject_handle,
2781 0,
2782 last_match_info_handle);
2783 if (match.is_null()) {
2784 return Failure::Exception();
2785 }
2786 if (match->IsNull()) {
2787 return *subject_handle;
2788 }
2789
2790 int capture_count = regexp_handle->CaptureCount();
2791
2792 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002793 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002794 CompiledReplacement compiled_replacement;
2795 compiled_replacement.Compile(replacement_handle,
2796 capture_count,
2797 length);
2798
2799 bool is_global = regexp_handle->GetFlags().is_global();
2800
2801 // Guessing the number of parts that the final result string is built
2802 // from. Global regexps can match any number of times, so we guess
2803 // conservatively.
2804 int expected_parts =
2805 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002806 ReplacementStringBuilder builder(isolate->heap(),
2807 subject_handle,
2808 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002809
2810 // Index of end of last match.
2811 int prev = 0;
2812
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002813 // Number of parts added by compiled replacement plus preceeding
2814 // string and possibly suffix after last match. It is possible for
2815 // all components to use two elements when encoded as two smis.
2816 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002817 bool matched = true;
2818 do {
2819 ASSERT(last_match_info_handle->HasFastElements());
2820 // Increase the capacity of the builder before entering local handle-scope,
2821 // so its internal buffer can safely allocate a new handle if it grows.
2822 builder.EnsureCapacity(parts_added_per_loop);
2823
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002824 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002825 int start, end;
2826 {
2827 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002828 FixedArray* match_info_array =
2829 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002830
2831 ASSERT_EQ(capture_count * 2 + 2,
2832 RegExpImpl::GetLastCaptureCount(match_info_array));
2833 start = RegExpImpl::GetCapture(match_info_array, 0);
2834 end = RegExpImpl::GetCapture(match_info_array, 1);
2835 }
2836
2837 if (prev < start) {
2838 builder.AddSubjectSlice(prev, start);
2839 }
2840 compiled_replacement.Apply(&builder,
2841 start,
2842 end,
2843 last_match_info_handle);
2844 prev = end;
2845
2846 // Only continue checking for global regexps.
2847 if (!is_global) break;
2848
2849 // Continue from where the match ended, unless it was an empty match.
2850 int next = end;
2851 if (start == end) {
2852 next = end + 1;
2853 if (next > length) break;
2854 }
2855
2856 match = RegExpImpl::Exec(regexp_handle,
2857 subject_handle,
2858 next,
2859 last_match_info_handle);
2860 if (match.is_null()) {
2861 return Failure::Exception();
2862 }
2863 matched = !match->IsNull();
2864 } while (matched);
2865
2866 if (prev < length) {
2867 builder.AddSubjectSlice(prev, length);
2868 }
2869
2870 return *(builder.ToString());
2871}
2872
2873
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002874template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002875MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002876 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002877 String* subject,
2878 JSRegExp* regexp,
2879 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002880 ASSERT(subject->IsFlat());
2881
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002882 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002883
2884 Handle<String> subject_handle(subject);
2885 Handle<JSRegExp> regexp_handle(regexp);
2886 Handle<JSArray> last_match_info_handle(last_match_info);
2887 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2888 subject_handle,
2889 0,
2890 last_match_info_handle);
2891 if (match.is_null()) return Failure::Exception();
2892 if (match->IsNull()) return *subject_handle;
2893
2894 ASSERT(last_match_info_handle->HasFastElements());
2895
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002896 int start, end;
2897 {
2898 AssertNoAllocation match_info_array_is_not_in_a_handle;
2899 FixedArray* match_info_array =
2900 FixedArray::cast(last_match_info_handle->elements());
2901
2902 start = RegExpImpl::GetCapture(match_info_array, 0);
2903 end = RegExpImpl::GetCapture(match_info_array, 1);
2904 }
2905
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002906 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002907 int new_length = length - (end - start);
2908 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002909 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002910 }
2911 Handle<ResultSeqString> answer;
2912 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002913 answer = Handle<ResultSeqString>::cast(
2914 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002915 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002916 answer = Handle<ResultSeqString>::cast(
2917 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002918 }
2919
2920 // If the regexp isn't global, only match once.
2921 if (!regexp_handle->GetFlags().is_global()) {
2922 if (start > 0) {
2923 String::WriteToFlat(*subject_handle,
2924 answer->GetChars(),
2925 0,
2926 start);
2927 }
2928 if (end < length) {
2929 String::WriteToFlat(*subject_handle,
2930 answer->GetChars() + start,
2931 end,
2932 length);
2933 }
2934 return *answer;
2935 }
2936
2937 int prev = 0; // Index of end of last match.
2938 int next = 0; // Start of next search (prev unless last match was empty).
2939 int position = 0;
2940
2941 do {
2942 if (prev < start) {
2943 // Add substring subject[prev;start] to answer string.
2944 String::WriteToFlat(*subject_handle,
2945 answer->GetChars() + position,
2946 prev,
2947 start);
2948 position += start - prev;
2949 }
2950 prev = end;
2951 next = end;
2952 // Continue from where the match ended, unless it was an empty match.
2953 if (start == end) {
2954 next++;
2955 if (next > length) break;
2956 }
2957 match = RegExpImpl::Exec(regexp_handle,
2958 subject_handle,
2959 next,
2960 last_match_info_handle);
2961 if (match.is_null()) return Failure::Exception();
2962 if (match->IsNull()) break;
2963
2964 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002965 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002966 {
2967 AssertNoAllocation match_info_array_is_not_in_a_handle;
2968 FixedArray* match_info_array =
2969 FixedArray::cast(last_match_info_handle->elements());
2970 start = RegExpImpl::GetCapture(match_info_array, 0);
2971 end = RegExpImpl::GetCapture(match_info_array, 1);
2972 }
2973 } while (true);
2974
2975 if (prev < length) {
2976 // Add substring subject[prev;length] to answer string.
2977 String::WriteToFlat(*subject_handle,
2978 answer->GetChars() + position,
2979 prev,
2980 length);
2981 position += length - prev;
2982 }
2983
2984 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002985 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002986 }
2987
2988 // Shorten string and fill
2989 int string_size = ResultSeqString::SizeFor(position);
2990 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2991 int delta = allocated_string_size - string_size;
2992
2993 answer->set_length(position);
2994 if (delta == 0) return *answer;
2995
2996 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002997 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002998
2999 return *answer;
3000}
3001
3002
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003003RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003004 ASSERT(args.length() == 4);
3005
3006 CONVERT_CHECKED(String, subject, args[0]);
3007 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003008 Object* flat_subject;
3009 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3010 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3011 return maybe_flat_subject;
3012 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003013 }
3014 subject = String::cast(flat_subject);
3015 }
3016
3017 CONVERT_CHECKED(String, replacement, args[2]);
3018 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003019 Object* flat_replacement;
3020 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3021 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3022 return maybe_flat_replacement;
3023 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003024 }
3025 replacement = String::cast(flat_replacement);
3026 }
3027
3028 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3029 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3030
3031 ASSERT(last_match_info->HasFastElements());
3032
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003033 if (replacement->length() == 0) {
3034 if (subject->HasOnlyAsciiChars()) {
3035 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003036 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003037 } else {
3038 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003039 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003040 }
3041 }
3042
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003043 return StringReplaceRegExpWithString(isolate,
3044 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003045 regexp,
3046 replacement,
3047 last_match_info);
3048}
3049
3050
ager@chromium.org7c537e22008-10-16 08:43:32 +00003051// Perform string match of pattern on subject, starting at start index.
3052// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003053// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003054int Runtime::StringMatch(Isolate* isolate,
3055 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003056 Handle<String> pat,
3057 int start_index) {
3058 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003059 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003060
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003061 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003062 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003063
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003064 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003065 if (start_index + pattern_length > subject_length) return -1;
3066
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003067 if (!sub->IsFlat()) FlattenString(sub);
3068 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003069
ager@chromium.org7c537e22008-10-16 08:43:32 +00003070 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003071 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003072 String::FlatContent seq_sub = sub->GetFlatContent();
3073 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003074
ager@chromium.org7c537e22008-10-16 08:43:32 +00003075 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003076 if (seq_pat.IsAscii()) {
3077 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3078 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003079 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003080 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003081 pat_vector,
3082 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003083 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003084 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003085 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003086 pat_vector,
3087 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003088 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003089 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3090 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003091 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003092 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003093 pat_vector,
3094 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003095 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003096 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003097 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003098 pat_vector,
3099 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003100}
3101
3102
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003103RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003104 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003105 ASSERT(args.length() == 3);
3106
ager@chromium.org7c537e22008-10-16 08:43:32 +00003107 CONVERT_ARG_CHECKED(String, sub, 0);
3108 CONVERT_ARG_CHECKED(String, pat, 1);
3109
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003110 Object* index = args[2];
3111 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003112 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003113
ager@chromium.org870a0b62008-11-04 11:43:05 +00003114 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003115 int position =
3116 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003117 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003118}
3119
3120
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003121template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003122static int StringMatchBackwards(Vector<const schar> subject,
3123 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003124 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003125 int pattern_length = pattern.length();
3126 ASSERT(pattern_length >= 1);
3127 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003128
3129 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003130 for (int i = 0; i < pattern_length; i++) {
3131 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003132 if (c > String::kMaxAsciiCharCode) {
3133 return -1;
3134 }
3135 }
3136 }
3137
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003138 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003139 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003140 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003141 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003142 while (j < pattern_length) {
3143 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003144 break;
3145 }
3146 j++;
3147 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003148 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003149 return i;
3150 }
3151 }
3152 return -1;
3153}
3154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003155RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003156 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003157 ASSERT(args.length() == 3);
3158
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003159 CONVERT_ARG_CHECKED(String, sub, 0);
3160 CONVERT_ARG_CHECKED(String, pat, 1);
3161
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003162 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003163 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003164 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003165
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003166 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003167 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003168
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003169 if (start_index + pat_length > sub_length) {
3170 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003171 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003172
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003173 if (pat_length == 0) {
3174 return Smi::FromInt(start_index);
3175 }
3176
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003177 if (!sub->IsFlat()) FlattenString(sub);
3178 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003179
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003180 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003181 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3182
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003183 String::FlatContent sub_content = sub->GetFlatContent();
3184 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003185
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003186 if (pat_content.IsAscii()) {
3187 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3188 if (sub_content.IsAscii()) {
3189 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003190 pat_vector,
3191 start_index);
3192 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003193 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003194 pat_vector,
3195 start_index);
3196 }
3197 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003198 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3199 if (sub_content.IsAscii()) {
3200 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003201 pat_vector,
3202 start_index);
3203 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003204 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003205 pat_vector,
3206 start_index);
3207 }
3208 }
3209
3210 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003211}
3212
3213
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003214RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003215 NoHandleAllocation ha;
3216 ASSERT(args.length() == 2);
3217
3218 CONVERT_CHECKED(String, str1, args[0]);
3219 CONVERT_CHECKED(String, str2, args[1]);
3220
3221 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003222 int str1_length = str1->length();
3223 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003224
3225 // Decide trivial cases without flattening.
3226 if (str1_length == 0) {
3227 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3228 return Smi::FromInt(-str2_length);
3229 } else {
3230 if (str2_length == 0) return Smi::FromInt(str1_length);
3231 }
3232
3233 int end = str1_length < str2_length ? str1_length : str2_length;
3234
3235 // No need to flatten if we are going to find the answer on the first
3236 // character. At this point we know there is at least one character
3237 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003238 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003239 if (d != 0) return Smi::FromInt(d);
3240
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003241 str1->TryFlatten();
3242 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003243
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003244 StringInputBuffer& buf1 =
3245 *isolate->runtime_state()->string_locale_compare_buf1();
3246 StringInputBuffer& buf2 =
3247 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003248
3249 buf1.Reset(str1);
3250 buf2.Reset(str2);
3251
3252 for (int i = 0; i < end; i++) {
3253 uint16_t char1 = buf1.GetNext();
3254 uint16_t char2 = buf2.GetNext();
3255 if (char1 != char2) return Smi::FromInt(char1 - char2);
3256 }
3257
3258 return Smi::FromInt(str1_length - str2_length);
3259}
3260
3261
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003262RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003263 NoHandleAllocation ha;
3264 ASSERT(args.length() == 3);
3265
3266 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003267 int start, end;
3268 // We have a fast integer-only case here to avoid a conversion to double in
3269 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003270 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3271 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3272 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3273 start = from_number;
3274 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003275 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003276 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3277 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003278 start = FastD2I(from_number);
3279 end = FastD2I(to_number);
3280 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003281 RUNTIME_ASSERT(end >= start);
3282 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003283 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003284 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003285 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003286}
3287
3288
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003289RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003290 ASSERT_EQ(3, args.length());
3291
3292 CONVERT_ARG_CHECKED(String, subject, 0);
3293 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3294 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3295 HandleScope handles;
3296
3297 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3298
3299 if (match.is_null()) {
3300 return Failure::Exception();
3301 }
3302 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003303 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003304 }
3305 int length = subject->length();
3306
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003307 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003308 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003309 int start;
3310 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003311 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003312 {
3313 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003314 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003315 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3316 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3317 }
3318 offsets.Add(start);
3319 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003320 if (start == end) if (++end > length) break;
3321 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003322 if (match.is_null()) {
3323 return Failure::Exception();
3324 }
3325 } while (!match->IsNull());
3326 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003327 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003328 Handle<String> substring = isolate->factory()->
3329 NewSubString(subject, offsets.at(0), offsets.at(1));
3330 elements->set(0, *substring);
3331 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003332 int from = offsets.at(i * 2);
3333 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003334 Handle<String> substring = isolate->factory()->
3335 NewProperSubString(subject, from, to);
3336 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003337 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003338 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003339 result->set_length(Smi::FromInt(matches));
3340 return *result;
3341}
3342
3343
lrn@chromium.org25156de2010-04-06 13:10:27 +00003344// Two smis before and after the match, for very long strings.
3345const int kMaxBuilderEntriesPerRegExpMatch = 5;
3346
3347
3348static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3349 Handle<JSArray> last_match_info,
3350 int match_start,
3351 int match_end) {
3352 // Fill last_match_info with a single capture.
3353 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3354 AssertNoAllocation no_gc;
3355 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3356 RegExpImpl::SetLastCaptureCount(elements, 2);
3357 RegExpImpl::SetLastInput(elements, *subject);
3358 RegExpImpl::SetLastSubject(elements, *subject);
3359 RegExpImpl::SetCapture(elements, 0, match_start);
3360 RegExpImpl::SetCapture(elements, 1, match_end);
3361}
3362
3363
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003364template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003365static bool SearchStringMultiple(Isolate* isolate,
3366 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003367 Vector<const PatternChar> pattern,
3368 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003369 FixedArrayBuilder* builder,
3370 int* match_pos) {
3371 int pos = *match_pos;
3372 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003373 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003374 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003375 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003376 while (pos <= max_search_start) {
3377 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3378 *match_pos = pos;
3379 return false;
3380 }
3381 // Position of end of previous match.
3382 int match_end = pos + pattern_length;
3383 int new_pos = search.Search(subject, match_end);
3384 if (new_pos >= 0) {
3385 // A match.
3386 if (new_pos > match_end) {
3387 ReplacementStringBuilder::AddSubjectSlice(builder,
3388 match_end,
3389 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003390 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003391 pos = new_pos;
3392 builder->Add(pattern_string);
3393 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003394 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003395 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003396 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003397
lrn@chromium.org25156de2010-04-06 13:10:27 +00003398 if (pos < max_search_start) {
3399 ReplacementStringBuilder::AddSubjectSlice(builder,
3400 pos + pattern_length,
3401 subject_length);
3402 }
3403 *match_pos = pos;
3404 return true;
3405}
3406
3407
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003408static bool SearchStringMultiple(Isolate* isolate,
3409 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003410 Handle<String> pattern,
3411 Handle<JSArray> last_match_info,
3412 FixedArrayBuilder* builder) {
3413 ASSERT(subject->IsFlat());
3414 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003415
3416 // Treating as if a previous match was before first character.
3417 int match_pos = -pattern->length();
3418
3419 for (;;) { // Break when search complete.
3420 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3421 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003422 String::FlatContent subject_content = subject->GetFlatContent();
3423 String::FlatContent pattern_content = pattern->GetFlatContent();
3424 if (subject_content.IsAscii()) {
3425 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3426 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003427 if (SearchStringMultiple(isolate,
3428 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003429 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003430 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003431 builder,
3432 &match_pos)) break;
3433 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003434 if (SearchStringMultiple(isolate,
3435 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003436 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003437 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003438 builder,
3439 &match_pos)) break;
3440 }
3441 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003442 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3443 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003444 if (SearchStringMultiple(isolate,
3445 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003446 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003447 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003448 builder,
3449 &match_pos)) break;
3450 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003451 if (SearchStringMultiple(isolate,
3452 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003453 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003454 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003455 builder,
3456 &match_pos)) break;
3457 }
3458 }
3459 }
3460
3461 if (match_pos >= 0) {
3462 SetLastMatchInfoNoCaptures(subject,
3463 last_match_info,
3464 match_pos,
3465 match_pos + pattern->length());
3466 return true;
3467 }
3468 return false; // No matches at all.
3469}
3470
3471
3472static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003473 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003474 Handle<String> subject,
3475 Handle<JSRegExp> regexp,
3476 Handle<JSArray> last_match_array,
3477 FixedArrayBuilder* builder) {
3478 ASSERT(subject->IsFlat());
3479 int match_start = -1;
3480 int match_end = 0;
3481 int pos = 0;
3482 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3483 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3484
3485 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003486 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003487 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003488 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003489
3490 for (;;) { // Break on failure, return on exception.
3491 RegExpImpl::IrregexpResult result =
3492 RegExpImpl::IrregexpExecOnce(regexp,
3493 subject,
3494 pos,
3495 register_vector);
3496 if (result == RegExpImpl::RE_SUCCESS) {
3497 match_start = register_vector[0];
3498 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3499 if (match_end < match_start) {
3500 ReplacementStringBuilder::AddSubjectSlice(builder,
3501 match_end,
3502 match_start);
3503 }
3504 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003505 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003506 if (!first) {
3507 builder->Add(*isolate->factory()->NewProperSubString(subject,
3508 match_start,
3509 match_end));
3510 } else {
3511 builder->Add(*isolate->factory()->NewSubString(subject,
3512 match_start,
3513 match_end));
3514 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003515 if (match_start != match_end) {
3516 pos = match_end;
3517 } else {
3518 pos = match_end + 1;
3519 if (pos > subject_length) break;
3520 }
3521 } else if (result == RegExpImpl::RE_FAILURE) {
3522 break;
3523 } else {
3524 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3525 return result;
3526 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003527 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003528 }
3529
3530 if (match_start >= 0) {
3531 if (match_end < subject_length) {
3532 ReplacementStringBuilder::AddSubjectSlice(builder,
3533 match_end,
3534 subject_length);
3535 }
3536 SetLastMatchInfoNoCaptures(subject,
3537 last_match_array,
3538 match_start,
3539 match_end);
3540 return RegExpImpl::RE_SUCCESS;
3541 } else {
3542 return RegExpImpl::RE_FAILURE; // No matches at all.
3543 }
3544}
3545
3546
3547static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003548 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003549 Handle<String> subject,
3550 Handle<JSRegExp> regexp,
3551 Handle<JSArray> last_match_array,
3552 FixedArrayBuilder* builder) {
3553
3554 ASSERT(subject->IsFlat());
3555 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3556 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3557
3558 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003559 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003560
3561 RegExpImpl::IrregexpResult result =
3562 RegExpImpl::IrregexpExecOnce(regexp,
3563 subject,
3564 0,
3565 register_vector);
3566
3567 int capture_count = regexp->CaptureCount();
3568 int subject_length = subject->length();
3569
3570 // Position to search from.
3571 int pos = 0;
3572 // End of previous match. Differs from pos if match was empty.
3573 int match_end = 0;
3574 if (result == RegExpImpl::RE_SUCCESS) {
3575 // Need to keep a copy of the previous match for creating last_match_info
3576 // at the end, so we have two vectors that we swap between.
3577 OffsetsVector registers2(required_registers);
3578 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003579 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003580 do {
3581 int match_start = register_vector[0];
3582 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3583 if (match_end < match_start) {
3584 ReplacementStringBuilder::AddSubjectSlice(builder,
3585 match_end,
3586 match_start);
3587 }
3588 match_end = register_vector[1];
3589
3590 {
3591 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003592 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003593 // Arguments array to replace function is match, captures, index and
3594 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003595 Handle<FixedArray> elements =
3596 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003597 Handle<String> match;
3598 if (!first) {
3599 match = isolate->factory()->NewProperSubString(subject,
3600 match_start,
3601 match_end);
3602 } else {
3603 match = isolate->factory()->NewSubString(subject,
3604 match_start,
3605 match_end);
3606 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003607 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003608 for (int i = 1; i <= capture_count; i++) {
3609 int start = register_vector[i * 2];
3610 if (start >= 0) {
3611 int end = register_vector[i * 2 + 1];
3612 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003613 Handle<String> substring;
3614 if (!first) {
3615 substring = isolate->factory()->NewProperSubString(subject,
3616 start,
3617 end);
3618 } else {
3619 substring = isolate->factory()->NewSubString(subject, start, end);
3620 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003621 elements->set(i, *substring);
3622 } else {
3623 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003624 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003625 }
3626 }
3627 elements->set(capture_count + 1, Smi::FromInt(match_start));
3628 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003629 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003630 }
3631 // Swap register vectors, so the last successful match is in
3632 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003633 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003634 prev_register_vector = register_vector;
3635 register_vector = tmp;
3636
3637 if (match_end > match_start) {
3638 pos = match_end;
3639 } else {
3640 pos = match_end + 1;
3641 if (pos > subject_length) {
3642 break;
3643 }
3644 }
3645
3646 result = RegExpImpl::IrregexpExecOnce(regexp,
3647 subject,
3648 pos,
3649 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003650 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003651 } while (result == RegExpImpl::RE_SUCCESS);
3652
3653 if (result != RegExpImpl::RE_EXCEPTION) {
3654 // Finished matching, with at least one match.
3655 if (match_end < subject_length) {
3656 ReplacementStringBuilder::AddSubjectSlice(builder,
3657 match_end,
3658 subject_length);
3659 }
3660
3661 int last_match_capture_count = (capture_count + 1) * 2;
3662 int last_match_array_size =
3663 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3664 last_match_array->EnsureSize(last_match_array_size);
3665 AssertNoAllocation no_gc;
3666 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3667 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3668 RegExpImpl::SetLastSubject(elements, *subject);
3669 RegExpImpl::SetLastInput(elements, *subject);
3670 for (int i = 0; i < last_match_capture_count; i++) {
3671 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3672 }
3673 return RegExpImpl::RE_SUCCESS;
3674 }
3675 }
3676 // No matches at all, return failure or exception result directly.
3677 return result;
3678}
3679
3680
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003681RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003682 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003683 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003684
3685 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003686 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003687 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3688 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3689 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3690
3691 ASSERT(last_match_info->HasFastElements());
3692 ASSERT(regexp->GetFlags().is_global());
3693 Handle<FixedArray> result_elements;
3694 if (result_array->HasFastElements()) {
3695 result_elements =
3696 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003697 }
3698 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003699 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003700 }
3701 FixedArrayBuilder builder(result_elements);
3702
3703 if (regexp->TypeTag() == JSRegExp::ATOM) {
3704 Handle<String> pattern(
3705 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003706 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003707 if (SearchStringMultiple(isolate, subject, pattern,
3708 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003709 return *builder.ToJSArray(result_array);
3710 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003711 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003712 }
3713
3714 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3715
3716 RegExpImpl::IrregexpResult result;
3717 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003718 result = SearchRegExpNoCaptureMultiple(isolate,
3719 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003720 regexp,
3721 last_match_info,
3722 &builder);
3723 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003724 result = SearchRegExpMultiple(isolate,
3725 subject,
3726 regexp,
3727 last_match_info,
3728 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003729 }
3730 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003731 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003732 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3733 return Failure::Exception();
3734}
3735
3736
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003737RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003738 NoHandleAllocation ha;
3739 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003740 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003741 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003742
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003743 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003744 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003745 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003746 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003747 // Character array used for conversion.
3748 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003749 return isolate->heap()->
3750 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003751 }
3752 }
3753
3754 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003755 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003756 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003757 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003758 }
3759 if (isinf(value)) {
3760 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003761 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003762 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003763 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003764 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003765 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003766 MaybeObject* result =
3767 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003768 DeleteArray(str);
3769 return result;
3770}
3771
3772
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003773RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003774 NoHandleAllocation ha;
3775 ASSERT(args.length() == 2);
3776
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003777 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003778 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003779 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003780 }
3781 if (isinf(value)) {
3782 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003783 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003784 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003785 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003786 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003787 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003788 int f = FastD2I(f_number);
3789 RUNTIME_ASSERT(f >= 0);
3790 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003791 MaybeObject* res =
3792 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003793 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003794 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003795}
3796
3797
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003798RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003799 NoHandleAllocation ha;
3800 ASSERT(args.length() == 2);
3801
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003802 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003803 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003804 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003805 }
3806 if (isinf(value)) {
3807 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003808 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003809 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003810 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003811 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003812 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003813 int f = FastD2I(f_number);
3814 RUNTIME_ASSERT(f >= -1 && f <= 20);
3815 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003816 MaybeObject* res =
3817 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003818 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003819 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003820}
3821
3822
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003823RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003824 NoHandleAllocation ha;
3825 ASSERT(args.length() == 2);
3826
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003827 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003828 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003829 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003830 }
3831 if (isinf(value)) {
3832 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003833 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003834 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003835 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003836 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003837 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003838 int f = FastD2I(f_number);
3839 RUNTIME_ASSERT(f >= 1 && f <= 21);
3840 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003841 MaybeObject* res =
3842 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003843 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003844 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003845}
3846
3847
3848// Returns a single character string where first character equals
3849// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003850static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003851 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003852 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003853 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003854 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003855 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003856 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003857}
3858
3859
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003860MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3861 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003862 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003863 // Handle [] indexing on Strings
3864 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003865 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3866 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003867 }
3868
3869 // Handle [] indexing on String objects
3870 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003871 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3872 Handle<Object> result =
3873 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3874 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003875 }
3876
3877 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003878 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003879 return prototype->GetElement(index);
3880 }
3881
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003882 return GetElement(object, index);
3883}
3884
3885
lrn@chromium.org303ada72010-10-27 09:33:13 +00003886MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003887 return object->GetElement(index);
3888}
3889
3890
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003891MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3892 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003893 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003894 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003895
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003896 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003897 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003898 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003899 isolate->factory()->NewTypeError("non_object_property_load",
3900 HandleVector(args, 2));
3901 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003902 }
3903
3904 // Check if the given key is an array index.
3905 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003906 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003907 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003908 }
3909
3910 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003911 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003912 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003913 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003914 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003915 bool has_pending_exception = false;
3916 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003917 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003918 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003919 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003920 }
3921
ager@chromium.org32912102009-01-16 10:38:43 +00003922 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003923 // the element if so.
3924 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003925 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003926 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003927 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003928 }
3929}
3930
3931
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003932RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003933 NoHandleAllocation ha;
3934 ASSERT(args.length() == 2);
3935
3936 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003937 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003938
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003939 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003940}
3941
3942
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003943// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003944RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003945 NoHandleAllocation ha;
3946 ASSERT(args.length() == 2);
3947
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003948 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003949 // itself.
3950 //
3951 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003952 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003953 // global proxy object never has properties. This is the case
3954 // because the global proxy object forwards everything to its hidden
3955 // prototype including local lookups.
3956 //
3957 // Additionally, we need to make sure that we do not cache results
3958 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003959 if (args[0]->IsJSObject() &&
3960 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003961 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003962 args[1]->IsString()) {
3963 JSObject* receiver = JSObject::cast(args[0]);
3964 String* key = String::cast(args[1]);
3965 if (receiver->HasFastProperties()) {
3966 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003967 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003968 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3969 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003970 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003971 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003972 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003973 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003974 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003975 LookupResult result;
3976 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003977 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003978 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003979 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003980 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003981 }
3982 } else {
3983 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003984 StringDictionary* dictionary = receiver->property_dictionary();
3985 int entry = dictionary->FindEntry(key);
3986 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003987 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003988 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003989 if (!receiver->IsGlobalObject()) return value;
3990 value = JSGlobalPropertyCell::cast(value)->value();
3991 if (!value->IsTheHole()) return value;
3992 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003993 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003994 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003995 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3996 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003997 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003998 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003999 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004000 if (index >= 0 && index < str->length()) {
4001 Handle<Object> result = GetCharAt(str, index);
4002 return *result;
4003 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004004 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004005
4006 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004007 return Runtime::GetObjectProperty(isolate,
4008 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004009 args.at<Object>(1));
4010}
4011
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004012// Implements part of 8.12.9 DefineOwnProperty.
4013// There are 3 cases that lead here:
4014// Step 4b - define a new accessor property.
4015// Steps 9c & 12 - replace an existing data property with an accessor property.
4016// Step 12 - update an existing accessor property with an accessor or generic
4017// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004018RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004019 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004020 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004021 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4022 CONVERT_CHECKED(String, name, args[1]);
4023 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004024 Object* fun = args[3];
4025 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004026 CONVERT_CHECKED(Smi, flag_attr, args[4]);
4027 int unchecked = flag_attr->value();
4028 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4029 RUNTIME_ASSERT(!obj->IsNull());
4030 LookupResult result;
4031 obj->LocalLookupRealNamedProperty(name, &result);
4032
4033 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4034 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
4035 // delete it to avoid running into trouble in DefineAccessor, which
4036 // handles this incorrectly if the property is readonly (does nothing)
4037 if (result.IsProperty() &&
4038 (result.type() == FIELD || result.type() == NORMAL
4039 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004040 Object* ok;
4041 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004042 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004043 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4044 }
ager@chromium.org5c838252010-02-19 08:53:10 +00004045 }
4046 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4047}
4048
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004049// Implements part of 8.12.9 DefineOwnProperty.
4050// There are 3 cases that lead here:
4051// Step 4a - define a new data property.
4052// Steps 9b & 12 - replace an existing accessor property with a data property.
4053// Step 12 - update an existing data property with a data or generic
4054// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004055RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004056 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004057 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004058 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4059 CONVERT_ARG_CHECKED(String, name, 1);
4060 Handle<Object> obj_value = args.at<Object>(2);
4061
4062 CONVERT_CHECKED(Smi, flag, args[3]);
4063 int unchecked = flag->value();
4064 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4065
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004066 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4067
4068 // Check if this is an element.
4069 uint32_t index;
4070 bool is_element = name->AsArrayIndex(&index);
4071
4072 // Special case for elements if any of the flags are true.
4073 // If elements are in fast case we always implicitly assume that:
4074 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4075 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
4076 is_element) {
4077 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004078 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004079 // We do not need to do access checks here since these has already
4080 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004081 Handle<Object> proto(js_object->GetPrototype());
4082 // If proxy is detached, ignore the assignment. Alternatively,
4083 // we could throw an exception.
4084 if (proto->IsNull()) return *obj_value;
4085 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004086 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004087 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004088 // Make sure that we never go back to fast case.
4089 dictionary->set_requires_slow_elements();
4090 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004091 Handle<NumberDictionary> extended_dictionary =
4092 NumberDictionarySet(dictionary, index, obj_value, details);
4093 if (*extended_dictionary != *dictionary) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004094 if (js_object->GetElementsKind() ==
4095 JSObject::NON_STRICT_ARGUMENTS_ELEMENTS) {
4096 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4097 } else {
4098 js_object->set_elements(*extended_dictionary);
4099 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004100 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004101 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004102 }
4103
ager@chromium.org5c838252010-02-19 08:53:10 +00004104 LookupResult result;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004105 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004106
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004107 // To be compatible with safari we do not change the value on API objects
4108 // in defineProperty. Firefox disagrees here, and actually changes the value.
4109 if (result.IsProperty() &&
4110 (result.type() == CALLBACKS) &&
4111 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004112 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004113 }
4114
ager@chromium.org5c838252010-02-19 08:53:10 +00004115 // Take special care when attributes are different and there is already
4116 // a property. For simplicity we normalize the property which enables us
4117 // to not worry about changing the instance_descriptor and creating a new
4118 // map. The current version of SetObjectProperty does not handle attributes
4119 // correctly in the case where a property is a field and is reset with
4120 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004121 if (result.IsProperty() &&
4122 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004123 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004124 if (js_object->IsJSGlobalProxy()) {
4125 // Since the result is a property, the prototype will exist so
4126 // we don't have to check for null.
4127 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004128 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004129 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004130 // Use IgnoreAttributes version since a readonly property may be
4131 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004132 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4133 *obj_value,
4134 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004135 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004136
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004137 return Runtime::ForceSetObjectProperty(isolate,
4138 js_object,
4139 name,
4140 obj_value,
4141 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004142}
4143
4144
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004145// Special case for elements if any of the flags are true.
4146// If elements are in fast case we always implicitly assume that:
4147// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4148static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4149 Handle<JSObject> js_object,
4150 uint32_t index,
4151 Handle<Object> value,
4152 PropertyAttributes attr) {
4153 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004154 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004155 // Make sure that we never go back to fast case.
4156 dictionary->set_requires_slow_elements();
4157 PropertyDetails details = PropertyDetails(attr, NORMAL);
4158 Handle<NumberDictionary> extended_dictionary =
4159 NumberDictionarySet(dictionary, index, value, details);
4160 if (*extended_dictionary != *dictionary) {
4161 js_object->set_elements(*extended_dictionary);
4162 }
4163 return *value;
4164}
4165
4166
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004167MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4168 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004169 Handle<Object> key,
4170 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004171 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004172 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004173 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004174
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004175 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004176 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004177 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004178 isolate->factory()->NewTypeError("non_object_property_store",
4179 HandleVector(args, 2));
4180 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004181 }
4182
4183 // If the object isn't a JavaScript object, we ignore the store.
4184 if (!object->IsJSObject()) return *value;
4185
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004186 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4187
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004188 // Check if the given key is an array index.
4189 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004190 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004191 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4192 // of a string using [] notation. We need to support this too in
4193 // JavaScript.
4194 // In the case of a String object we just need to redirect the assignment to
4195 // the underlying string if the index is in range. Since the underlying
4196 // string does nothing with the assignment then we can ignore such
4197 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004198 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004199 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004200 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004201
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004202 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4203 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4204 }
4205
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004206 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004207 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004208 return *value;
4209 }
4210
4211 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004212 Handle<Object> result;
4213 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004214 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4215 return NormalizeObjectSetElement(isolate,
4216 js_object,
4217 index,
4218 value,
4219 attr);
4220 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004221 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004222 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004223 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004224 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004225 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004226 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004227 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004228 return *value;
4229 }
4230
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004231 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004232 bool has_pending_exception = false;
4233 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4234 if (has_pending_exception) return Failure::Exception();
4235 Handle<String> name = Handle<String>::cast(converted);
4236
4237 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004238 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004239 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004240 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004241 }
4242}
4243
4244
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004245MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4246 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004247 Handle<Object> key,
4248 Handle<Object> value,
4249 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004250 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004251
4252 // Check if the given key is an array index.
4253 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004254 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004255 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4256 // of a string using [] notation. We need to support this too in
4257 // JavaScript.
4258 // In the case of a String object we just need to redirect the assignment to
4259 // the underlying string if the index is in range. Since the underlying
4260 // string does nothing with the assignment then we can ignore such
4261 // assignments.
4262 if (js_object->IsStringObjectWithCharacterAt(index)) {
4263 return *value;
4264 }
4265
whesse@chromium.org7b260152011-06-20 15:33:18 +00004266 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004267 }
4268
4269 if (key->IsString()) {
4270 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004271 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004272 } else {
4273 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004274 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004275 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4276 *value,
4277 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004278 }
4279 }
4280
4281 // Call-back into JavaScript to convert the key to a string.
4282 bool has_pending_exception = false;
4283 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4284 if (has_pending_exception) return Failure::Exception();
4285 Handle<String> name = Handle<String>::cast(converted);
4286
4287 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004288 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004289 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004290 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004291 }
4292}
4293
4294
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004295MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004296 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004297 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004298 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004299
4300 // Check if the given key is an array index.
4301 uint32_t index;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004302 if (receiver->IsJSObject() && key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004303 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4304 // characters of a string using [] notation. In the case of a
4305 // String object we just need to redirect the deletion to the
4306 // underlying string if the index is in range. Since the
4307 // underlying string does nothing with the deletion, we can ignore
4308 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004309 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004310 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004311 }
4312
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004313 return JSObject::cast(*receiver)->DeleteElement(
4314 index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004315 }
4316
4317 Handle<String> key_string;
4318 if (key->IsString()) {
4319 key_string = Handle<String>::cast(key);
4320 } else {
4321 // Call-back into JavaScript to convert the key to a string.
4322 bool has_pending_exception = false;
4323 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4324 if (has_pending_exception) return Failure::Exception();
4325 key_string = Handle<String>::cast(converted);
4326 }
4327
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004328 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004329 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004330}
4331
4332
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004333RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004334 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004335 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004336
4337 Handle<Object> object = args.at<Object>(0);
4338 Handle<Object> key = args.at<Object>(1);
4339 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004340 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004341 RUNTIME_ASSERT(
4342 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004343 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004344 PropertyAttributes attributes =
4345 static_cast<PropertyAttributes>(unchecked_attributes);
4346
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004347 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004348 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004349 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004350 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4351 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004352 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004353 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004354
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004355 return Runtime::SetObjectProperty(isolate,
4356 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004357 key,
4358 value,
4359 attributes,
4360 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004361}
4362
4363
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004364// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004365// This is used to decide if we should transform null and undefined
4366// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004367RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004368 NoHandleAllocation ha;
4369 RUNTIME_ASSERT(args.length() == 1);
4370
4371 Handle<Object> object = args.at<Object>(0);
4372
4373 if (object->IsJSFunction()) {
4374 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004375 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004376 }
4377 return isolate->heap()->undefined_value();
4378}
4379
4380
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004381// Set a local property, even if it is READ_ONLY. If the property does not
4382// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004383RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004384 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004385 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004386 CONVERT_CHECKED(JSObject, object, args[0]);
4387 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004388 // Compute attributes.
4389 PropertyAttributes attributes = NONE;
4390 if (args.length() == 4) {
4391 CONVERT_CHECKED(Smi, value_obj, args[3]);
4392 int unchecked_value = value_obj->value();
4393 // Only attribute bits should be set.
4394 RUNTIME_ASSERT(
4395 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4396 attributes = static_cast<PropertyAttributes>(unchecked_value);
4397 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004398
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004399 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004400 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004401}
4402
4403
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004404RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004405 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004406 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004407
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004408 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004409 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004410 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004411 return object->DeleteProperty(key, (strict == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004412 ? JSReceiver::STRICT_DELETION
4413 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004414}
4415
4416
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004417static Object* HasLocalPropertyImplementation(Isolate* isolate,
4418 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004419 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004420 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004421 // Handle hidden prototypes. If there's a hidden prototype above this thing
4422 // then we have to check it for properties, because they are supposed to
4423 // look like they are on this object.
4424 Handle<Object> proto(object->GetPrototype());
4425 if (proto->IsJSObject() &&
4426 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004427 return HasLocalPropertyImplementation(isolate,
4428 Handle<JSObject>::cast(proto),
4429 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004430 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004431 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004432}
4433
4434
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004435RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004436 NoHandleAllocation ha;
4437 ASSERT(args.length() == 2);
4438 CONVERT_CHECKED(String, key, args[1]);
4439
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004440 uint32_t index;
4441 const bool key_is_array_index = key->AsArrayIndex(&index);
4442
ager@chromium.org9085a012009-05-11 19:22:57 +00004443 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004444 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004445 if (obj->IsJSObject()) {
4446 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004447 // Fast case: either the key is a real named property or it is not
4448 // an array index and there are no interceptors or hidden
4449 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004450 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004451 Map* map = object->map();
4452 if (!key_is_array_index &&
4453 !map->has_named_interceptor() &&
4454 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4455 return isolate->heap()->false_value();
4456 }
4457 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004458 HandleScope scope(isolate);
4459 return HasLocalPropertyImplementation(isolate,
4460 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004461 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004462 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004463 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004464 String* string = String::cast(obj);
4465 if (index < static_cast<uint32_t>(string->length())) {
4466 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004467 }
4468 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004469 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004470}
4471
4472
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004473RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004474 NoHandleAllocation na;
4475 ASSERT(args.length() == 2);
4476
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004477 // Only JS receivers can have properties.
4478 if (args[0]->IsJSReceiver()) {
4479 JSReceiver* receiver = JSReceiver::cast(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004480 CONVERT_CHECKED(String, key, args[1]);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004481 if (receiver->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004482 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004483 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004484}
4485
4486
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004487RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004488 NoHandleAllocation na;
4489 ASSERT(args.length() == 2);
4490
4491 // Only JS objects can have elements.
4492 if (args[0]->IsJSObject()) {
4493 JSObject* object = JSObject::cast(args[0]);
4494 CONVERT_CHECKED(Smi, index_obj, args[1]);
4495 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004496 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004497 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004498 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004499}
4500
4501
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004502RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004503 NoHandleAllocation ha;
4504 ASSERT(args.length() == 2);
4505
4506 CONVERT_CHECKED(JSObject, object, args[0]);
4507 CONVERT_CHECKED(String, key, args[1]);
4508
4509 uint32_t index;
4510 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004511 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004512 }
4513
ager@chromium.org870a0b62008-11-04 11:43:05 +00004514 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004515 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004516}
4517
4518
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004519RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004520 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004521 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004522 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004523 return *GetKeysFor(object);
4524}
4525
4526
4527// Returns either a FixedArray as Runtime_GetPropertyNames,
4528// or, if the given object has an enum cache that contains
4529// all enumerable properties of the object and its prototypes
4530// have none, the map of the object. This is used to speed up
4531// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004532RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004533 ASSERT(args.length() == 1);
4534
4535 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4536
4537 if (raw_object->IsSimpleEnum()) return raw_object->map();
4538
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004539 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004540 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004541 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4542 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004543
4544 // Test again, since cache may have been built by preceding call.
4545 if (object->IsSimpleEnum()) return object->map();
4546
4547 return *content;
4548}
4549
4550
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004551// Find the length of the prototype chain that is to to handled as one. If a
4552// prototype object is hidden it is to be viewed as part of the the object it
4553// is prototype for.
4554static int LocalPrototypeChainLength(JSObject* obj) {
4555 int count = 1;
4556 Object* proto = obj->GetPrototype();
4557 while (proto->IsJSObject() &&
4558 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4559 count++;
4560 proto = JSObject::cast(proto)->GetPrototype();
4561 }
4562 return count;
4563}
4564
4565
4566// Return the names of the local named properties.
4567// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004568RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004569 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004570 ASSERT(args.length() == 1);
4571 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004572 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004573 }
4574 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4575
4576 // Skip the global proxy as it has no properties and always delegates to the
4577 // real global object.
4578 if (obj->IsJSGlobalProxy()) {
4579 // Only collect names if access is permitted.
4580 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004581 !isolate->MayNamedAccess(*obj,
4582 isolate->heap()->undefined_value(),
4583 v8::ACCESS_KEYS)) {
4584 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4585 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004586 }
4587 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4588 }
4589
4590 // Find the number of objects making up this.
4591 int length = LocalPrototypeChainLength(*obj);
4592
4593 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004594 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004595 int total_property_count = 0;
4596 Handle<JSObject> jsproto = obj;
4597 for (int i = 0; i < length; i++) {
4598 // Only collect names if access is permitted.
4599 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004600 !isolate->MayNamedAccess(*jsproto,
4601 isolate->heap()->undefined_value(),
4602 v8::ACCESS_KEYS)) {
4603 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4604 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004605 }
4606 int n;
4607 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4608 local_property_count[i] = n;
4609 total_property_count += n;
4610 if (i < length - 1) {
4611 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4612 }
4613 }
4614
4615 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004616 Handle<FixedArray> names =
4617 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004618
4619 // Get the property names.
4620 jsproto = obj;
4621 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004622 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004623 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004624 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4625 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004626 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004627 proto_with_hidden_properties++;
4628 }
4629 if (i < length - 1) {
4630 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4631 }
4632 }
4633
4634 // Filter out name of hidden propeties object.
4635 if (proto_with_hidden_properties > 0) {
4636 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004637 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004638 names->length() - proto_with_hidden_properties);
4639 int dest_pos = 0;
4640 for (int i = 0; i < total_property_count; i++) {
4641 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004642 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004643 continue;
4644 }
4645 names->set(dest_pos++, name);
4646 }
4647 }
4648
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004649 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004650}
4651
4652
4653// Return the names of the local indexed properties.
4654// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004655RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004656 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004657 ASSERT(args.length() == 1);
4658 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004659 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004660 }
4661 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4662
4663 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004664 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004665 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004666 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004667}
4668
4669
4670// Return information on whether an object has a named or indexed interceptor.
4671// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004672RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004673 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004674 ASSERT(args.length() == 1);
4675 if (!args[0]->IsJSObject()) {
4676 return Smi::FromInt(0);
4677 }
4678 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4679
4680 int result = 0;
4681 if (obj->HasNamedInterceptor()) result |= 2;
4682 if (obj->HasIndexedInterceptor()) result |= 1;
4683
4684 return Smi::FromInt(result);
4685}
4686
4687
4688// Return property names from named interceptor.
4689// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004690RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004691 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004692 ASSERT(args.length() == 1);
4693 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4694
4695 if (obj->HasNamedInterceptor()) {
4696 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4697 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4698 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004699 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004700}
4701
4702
4703// Return element names from indexed interceptor.
4704// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004705RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004706 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004707 ASSERT(args.length() == 1);
4708 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4709
4710 if (obj->HasIndexedInterceptor()) {
4711 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4712 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4713 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004714 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004715}
4716
4717
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004718RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004719 ASSERT_EQ(args.length(), 1);
4720 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004721 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004722 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004723
4724 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004725 // Do access checks before going to the global object.
4726 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004727 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004728 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004729 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4730 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004731 }
4732
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004733 Handle<Object> proto(object->GetPrototype());
4734 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004735 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004736 object = Handle<JSObject>::cast(proto);
4737 }
4738
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004739 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4740 LOCAL_ONLY);
4741 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4742 // property array and since the result is mutable we have to create
4743 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004744 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004745 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004746 for (int i = 0; i < length; i++) {
4747 Object* entry = contents->get(i);
4748 if (entry->IsString()) {
4749 copy->set(i, entry);
4750 } else {
4751 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004752 HandleScope scope(isolate);
4753 Handle<Object> entry_handle(entry, isolate);
4754 Handle<Object> entry_str =
4755 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004756 copy->set(i, *entry_str);
4757 }
4758 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004759 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004760}
4761
4762
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004763RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004764 NoHandleAllocation ha;
4765 ASSERT(args.length() == 1);
4766
4767 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004768 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004769 it.AdvanceToArgumentsFrame();
4770 JavaScriptFrame* frame = it.frame();
4771
4772 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004773 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004774
4775 // Try to convert the key to an index. If successful and within
4776 // index return the the argument from the frame.
4777 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004778 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004779 return frame->GetParameter(index);
4780 }
4781
4782 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004783 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004784 bool exception = false;
4785 Handle<Object> converted =
4786 Execution::ToString(args.at<Object>(0), &exception);
4787 if (exception) return Failure::Exception();
4788 Handle<String> key = Handle<String>::cast(converted);
4789
4790 // Try to convert the string key into an array index.
4791 if (key->AsArrayIndex(&index)) {
4792 if (index < n) {
4793 return frame->GetParameter(index);
4794 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004795 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004796 }
4797 }
4798
4799 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004800 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4801 if (key->Equals(isolate->heap()->callee_symbol())) {
4802 Object* function = frame->function();
4803 if (function->IsJSFunction() &&
4804 JSFunction::cast(function)->shared()->strict_mode()) {
4805 return isolate->Throw(*isolate->factory()->NewTypeError(
4806 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4807 }
4808 return function;
4809 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004810
4811 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004812 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004813}
4814
4815
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004816RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004817 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004818
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004819 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004820 Handle<Object> object = args.at<Object>(0);
4821 if (object->IsJSObject()) {
4822 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004823 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004824 MaybeObject* ok = js_object->TransformToFastProperties(0);
4825 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004826 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004827 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004828 return *object;
4829}
4830
4831
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004832RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004833 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004834
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004835 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004836 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004837 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004838 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004839 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004840 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004841 return *object;
4842}
4843
4844
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004845RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004846 NoHandleAllocation ha;
4847 ASSERT(args.length() == 1);
4848
4849 return args[0]->ToBoolean();
4850}
4851
4852
4853// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4854// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004855RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004856 NoHandleAllocation ha;
4857
4858 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004859 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004860 HeapObject* heap_obj = HeapObject::cast(obj);
4861
4862 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004863 if (heap_obj->map()->is_undetectable()) {
4864 return isolate->heap()->undefined_symbol();
4865 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004866
4867 InstanceType instance_type = heap_obj->map()->instance_type();
4868 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004869 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004870 }
4871
4872 switch (instance_type) {
4873 case ODDBALL_TYPE:
4874 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004875 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004876 }
4877 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004878 return FLAG_harmony_typeof
4879 ? isolate->heap()->null_symbol()
4880 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004881 }
4882 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004883 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004884 case JS_FUNCTION_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004885 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004886 default:
4887 // For any kind of object not handled above, the spec rule for
4888 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004889 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004890 }
4891}
4892
4893
lrn@chromium.org25156de2010-04-06 13:10:27 +00004894static bool AreDigits(const char*s, int from, int to) {
4895 for (int i = from; i < to; i++) {
4896 if (s[i] < '0' || s[i] > '9') return false;
4897 }
4898
4899 return true;
4900}
4901
4902
4903static int ParseDecimalInteger(const char*s, int from, int to) {
4904 ASSERT(to - from < 10); // Overflow is not possible.
4905 ASSERT(from < to);
4906 int d = s[from] - '0';
4907
4908 for (int i = from + 1; i < to; i++) {
4909 d = 10 * d + (s[i] - '0');
4910 }
4911
4912 return d;
4913}
4914
4915
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004916RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004917 NoHandleAllocation ha;
4918 ASSERT(args.length() == 1);
4919 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004920 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004921
4922 // Fast case: short integer or some sorts of junk values.
4923 int len = subject->length();
4924 if (subject->IsSeqAsciiString()) {
4925 if (len == 0) return Smi::FromInt(0);
4926
4927 char const* data = SeqAsciiString::cast(subject)->GetChars();
4928 bool minus = (data[0] == '-');
4929 int start_pos = (minus ? 1 : 0);
4930
4931 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004932 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004933 } else if (data[start_pos] > '9') {
4934 // Fast check for a junk value. A valid string may start from a
4935 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4936 // the 'I' character ('Infinity'). All of that have codes not greater than
4937 // '9' except 'I'.
4938 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004939 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004940 }
4941 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4942 // The maximal/minimal smi has 10 digits. If the string has less digits we
4943 // know it will fit into the smi-data type.
4944 int d = ParseDecimalInteger(data, start_pos, len);
4945 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004946 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004947 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004948 } else if (!subject->HasHashCode() &&
4949 len <= String::kMaxArrayIndexSize &&
4950 (len == 1 || data[0] != '0')) {
4951 // String hash is not calculated yet but all the data are present.
4952 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004953 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004954#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004955 subject->Hash(); // Force hash calculation.
4956 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4957 static_cast<int>(hash));
4958#endif
4959 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004960 }
4961 return Smi::FromInt(d);
4962 }
4963 }
4964
4965 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004966 return isolate->heap()->NumberFromDouble(
4967 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004968}
4969
4970
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004971RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004972 NoHandleAllocation ha;
4973 ASSERT(args.length() == 1);
4974
4975 CONVERT_CHECKED(JSArray, codes, args[0]);
4976 int length = Smi::cast(codes->length())->value();
4977
4978 // Check if the string can be ASCII.
4979 int i;
4980 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004981 Object* element;
4982 { MaybeObject* maybe_element = codes->GetElement(i);
4983 // We probably can't get an exception here, but just in order to enforce
4984 // the checking of inputs in the runtime calls we check here.
4985 if (!maybe_element->ToObject(&element)) return maybe_element;
4986 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004987 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4988 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4989 break;
4990 }
4991
lrn@chromium.org303ada72010-10-27 09:33:13 +00004992 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004993 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004994 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004995 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004996 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004997 }
4998
lrn@chromium.org303ada72010-10-27 09:33:13 +00004999 Object* object = NULL;
5000 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005001 String* result = String::cast(object);
5002 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005003 Object* element;
5004 { MaybeObject* maybe_element = codes->GetElement(i);
5005 if (!maybe_element->ToObject(&element)) return maybe_element;
5006 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005007 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005008 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005009 }
5010 return result;
5011}
5012
5013
5014// kNotEscaped is generated by the following:
5015//
5016// #!/bin/perl
5017// for (my $i = 0; $i < 256; $i++) {
5018// print "\n" if $i % 16 == 0;
5019// my $c = chr($i);
5020// my $escaped = 1;
5021// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5022// print $escaped ? "0, " : "1, ";
5023// }
5024
5025
5026static bool IsNotEscaped(uint16_t character) {
5027 // Only for 8 bit characters, the rest are always escaped (in a different way)
5028 ASSERT(character < 256);
5029 static const char kNotEscaped[256] = {
5030 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5031 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5032 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5033 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5034 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5035 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5036 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5037 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5038 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5039 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5040 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5041 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5042 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5043 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5044 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5045 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5046 };
5047 return kNotEscaped[character] != 0;
5048}
5049
5050
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005051RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005052 const char hex_chars[] = "0123456789ABCDEF";
5053 NoHandleAllocation ha;
5054 ASSERT(args.length() == 1);
5055 CONVERT_CHECKED(String, source, args[0]);
5056
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005057 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005058
5059 int escaped_length = 0;
5060 int length = source->length();
5061 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005062 Access<StringInputBuffer> buffer(
5063 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005064 buffer->Reset(source);
5065 while (buffer->has_more()) {
5066 uint16_t character = buffer->GetNext();
5067 if (character >= 256) {
5068 escaped_length += 6;
5069 } else if (IsNotEscaped(character)) {
5070 escaped_length++;
5071 } else {
5072 escaped_length += 3;
5073 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005074 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005075 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005076 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005077 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005078 return Failure::OutOfMemoryException();
5079 }
5080 }
5081 }
5082 // No length change implies no change. Return original string if no change.
5083 if (escaped_length == length) {
5084 return source;
5085 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005086 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005087 { MaybeObject* maybe_o =
5088 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005089 if (!maybe_o->ToObject(&o)) return maybe_o;
5090 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005091 String* destination = String::cast(o);
5092 int dest_position = 0;
5093
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005094 Access<StringInputBuffer> buffer(
5095 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005096 buffer->Rewind();
5097 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005098 uint16_t chr = buffer->GetNext();
5099 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005100 destination->Set(dest_position, '%');
5101 destination->Set(dest_position+1, 'u');
5102 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5103 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5104 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5105 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005106 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005107 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005108 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005109 dest_position++;
5110 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005111 destination->Set(dest_position, '%');
5112 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5113 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005114 dest_position += 3;
5115 }
5116 }
5117 return destination;
5118}
5119
5120
5121static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5122 static const signed char kHexValue['g'] = {
5123 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5124 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5125 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5126 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5127 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5128 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5129 -1, 10, 11, 12, 13, 14, 15 };
5130
5131 if (character1 > 'f') return -1;
5132 int hi = kHexValue[character1];
5133 if (hi == -1) return -1;
5134 if (character2 > 'f') return -1;
5135 int lo = kHexValue[character2];
5136 if (lo == -1) return -1;
5137 return (hi << 4) + lo;
5138}
5139
5140
ager@chromium.org870a0b62008-11-04 11:43:05 +00005141static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005142 int i,
5143 int length,
5144 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005145 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005146 int32_t hi = 0;
5147 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005148 if (character == '%' &&
5149 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005150 source->Get(i + 1) == 'u' &&
5151 (hi = TwoDigitHex(source->Get(i + 2),
5152 source->Get(i + 3))) != -1 &&
5153 (lo = TwoDigitHex(source->Get(i + 4),
5154 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005155 *step = 6;
5156 return (hi << 8) + lo;
5157 } else if (character == '%' &&
5158 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005159 (lo = TwoDigitHex(source->Get(i + 1),
5160 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005161 *step = 3;
5162 return lo;
5163 } else {
5164 *step = 1;
5165 return character;
5166 }
5167}
5168
5169
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005170RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005171 NoHandleAllocation ha;
5172 ASSERT(args.length() == 1);
5173 CONVERT_CHECKED(String, source, args[0]);
5174
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005175 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005176
5177 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005178 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005179
5180 int unescaped_length = 0;
5181 for (int i = 0; i < length; unescaped_length++) {
5182 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005183 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005184 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005185 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005186 i += step;
5187 }
5188
5189 // No length change implies no change. Return original string if no change.
5190 if (unescaped_length == length)
5191 return source;
5192
lrn@chromium.org303ada72010-10-27 09:33:13 +00005193 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005194 { MaybeObject* maybe_o =
5195 ascii ?
5196 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5197 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005198 if (!maybe_o->ToObject(&o)) return maybe_o;
5199 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005200 String* destination = String::cast(o);
5201
5202 int dest_position = 0;
5203 for (int i = 0; i < length; dest_position++) {
5204 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005205 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005206 i += step;
5207 }
5208 return destination;
5209}
5210
5211
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005212static const unsigned int kQuoteTableLength = 128u;
5213
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005214static const int kJsonQuotesCharactersPerEntry = 8;
5215static const char* const JsonQuotes =
5216 "\\u0000 \\u0001 \\u0002 \\u0003 "
5217 "\\u0004 \\u0005 \\u0006 \\u0007 "
5218 "\\b \\t \\n \\u000b "
5219 "\\f \\r \\u000e \\u000f "
5220 "\\u0010 \\u0011 \\u0012 \\u0013 "
5221 "\\u0014 \\u0015 \\u0016 \\u0017 "
5222 "\\u0018 \\u0019 \\u001a \\u001b "
5223 "\\u001c \\u001d \\u001e \\u001f "
5224 " ! \\\" # "
5225 "$ % & ' "
5226 "( ) * + "
5227 ", - . / "
5228 "0 1 2 3 "
5229 "4 5 6 7 "
5230 "8 9 : ; "
5231 "< = > ? "
5232 "@ A B C "
5233 "D E F G "
5234 "H I J K "
5235 "L M N O "
5236 "P Q R S "
5237 "T U V W "
5238 "X Y Z [ "
5239 "\\\\ ] ^ _ "
5240 "` a b c "
5241 "d e f g "
5242 "h i j k "
5243 "l m n o "
5244 "p q r s "
5245 "t u v w "
5246 "x y z { "
5247 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005248
5249
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005250// For a string that is less than 32k characters it should always be
5251// possible to allocate it in new space.
5252static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5253
5254
5255// Doing JSON quoting cannot make the string more than this many times larger.
5256static const int kJsonQuoteWorstCaseBlowup = 6;
5257
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005258static const int kSpaceForQuotesAndComma = 3;
5259static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005260
5261// Covers the entire ASCII range (all other characters are unchanged by JSON
5262// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005263static const byte JsonQuoteLengths[kQuoteTableLength] = {
5264 6, 6, 6, 6, 6, 6, 6, 6,
5265 2, 2, 2, 6, 2, 2, 6, 6,
5266 6, 6, 6, 6, 6, 6, 6, 6,
5267 6, 6, 6, 6, 6, 6, 6, 6,
5268 1, 1, 2, 1, 1, 1, 1, 1,
5269 1, 1, 1, 1, 1, 1, 1, 1,
5270 1, 1, 1, 1, 1, 1, 1, 1,
5271 1, 1, 1, 1, 1, 1, 1, 1,
5272 1, 1, 1, 1, 1, 1, 1, 1,
5273 1, 1, 1, 1, 1, 1, 1, 1,
5274 1, 1, 1, 1, 1, 1, 1, 1,
5275 1, 1, 1, 1, 2, 1, 1, 1,
5276 1, 1, 1, 1, 1, 1, 1, 1,
5277 1, 1, 1, 1, 1, 1, 1, 1,
5278 1, 1, 1, 1, 1, 1, 1, 1,
5279 1, 1, 1, 1, 1, 1, 1, 1,
5280};
5281
5282
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005283template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005284MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005285
5286
5287template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005288MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5289 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005290}
5291
5292
5293template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005294MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5295 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005296}
5297
5298
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005299template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005300static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5301 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005302 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005303 const Char* read_cursor = characters.start();
5304 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005305 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005306 int quoted_length = kSpaceForQuotes;
5307 while (read_cursor < end) {
5308 Char c = *(read_cursor++);
5309 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5310 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005311 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005312 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005313 }
5314 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005315 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5316 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005317 Object* new_object;
5318 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005319 return new_alloc;
5320 }
5321 StringType* new_string = StringType::cast(new_object);
5322
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005323 Char* write_cursor = reinterpret_cast<Char*>(
5324 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005325 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005326 *(write_cursor++) = '"';
5327
5328 read_cursor = characters.start();
5329 while (read_cursor < end) {
5330 Char c = *(read_cursor++);
5331 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5332 *(write_cursor++) = c;
5333 } else {
5334 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5335 const char* replacement = JsonQuotes +
5336 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5337 for (int i = 0; i < len; i++) {
5338 *write_cursor++ = *replacement++;
5339 }
5340 }
5341 }
5342 *(write_cursor++) = '"';
5343 return new_string;
5344}
5345
5346
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005347template <typename SinkChar, typename SourceChar>
5348static inline SinkChar* WriteQuoteJsonString(
5349 Isolate* isolate,
5350 SinkChar* write_cursor,
5351 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005352 // SinkChar is only char if SourceChar is guaranteed to be char.
5353 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005354 const SourceChar* read_cursor = characters.start();
5355 const SourceChar* end = read_cursor + characters.length();
5356 *(write_cursor++) = '"';
5357 while (read_cursor < end) {
5358 SourceChar c = *(read_cursor++);
5359 if (sizeof(SourceChar) > 1u &&
5360 static_cast<unsigned>(c) >= kQuoteTableLength) {
5361 *(write_cursor++) = static_cast<SinkChar>(c);
5362 } else {
5363 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5364 const char* replacement = JsonQuotes +
5365 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5366 write_cursor[0] = replacement[0];
5367 if (len > 1) {
5368 write_cursor[1] = replacement[1];
5369 if (len > 2) {
5370 ASSERT(len == 6);
5371 write_cursor[2] = replacement[2];
5372 write_cursor[3] = replacement[3];
5373 write_cursor[4] = replacement[4];
5374 write_cursor[5] = replacement[5];
5375 }
5376 }
5377 write_cursor += len;
5378 }
5379 }
5380 *(write_cursor++) = '"';
5381 return write_cursor;
5382}
5383
5384
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005385template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005386static MaybeObject* QuoteJsonString(Isolate* isolate,
5387 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005388 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005389 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005390 int worst_case_length =
5391 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005392 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005393 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005394 }
5395
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005396 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5397 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005398 Object* new_object;
5399 if (!new_alloc->ToObject(&new_object)) {
5400 return new_alloc;
5401 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005402 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005403 // Even if our string is small enough to fit in new space we still have to
5404 // handle it being allocated in old space as may happen in the third
5405 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5406 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005407 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005408 }
5409 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005410 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005411
5412 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5413 Char* write_cursor = reinterpret_cast<Char*>(
5414 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005415 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005416 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5417 write_cursor,
5418 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005419 int final_length = static_cast<int>(
5420 write_cursor - reinterpret_cast<Char*>(
5421 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005422 isolate->heap()->new_space()->
5423 template ShrinkStringAtAllocationBoundary<StringType>(
5424 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005425 return new_string;
5426}
5427
5428
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005429RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005430 NoHandleAllocation ha;
5431 CONVERT_CHECKED(String, str, args[0]);
5432 if (!str->IsFlat()) {
5433 MaybeObject* try_flatten = str->TryFlatten();
5434 Object* flat;
5435 if (!try_flatten->ToObject(&flat)) {
5436 return try_flatten;
5437 }
5438 str = String::cast(flat);
5439 ASSERT(str->IsFlat());
5440 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005441 String::FlatContent flat = str->GetFlatContent();
5442 ASSERT(flat.IsFlat());
5443 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005444 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005445 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005446 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005447 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005448 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005449 }
5450}
5451
5452
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005453RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005454 NoHandleAllocation ha;
5455 CONVERT_CHECKED(String, str, args[0]);
5456 if (!str->IsFlat()) {
5457 MaybeObject* try_flatten = str->TryFlatten();
5458 Object* flat;
5459 if (!try_flatten->ToObject(&flat)) {
5460 return try_flatten;
5461 }
5462 str = String::cast(flat);
5463 ASSERT(str->IsFlat());
5464 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005465 String::FlatContent flat = str->GetFlatContent();
5466 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005467 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005468 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005469 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005470 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005471 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005472 }
5473}
5474
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005475
5476template <typename Char, typename StringType>
5477static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5478 FixedArray* array,
5479 int worst_case_length) {
5480 int length = array->length();
5481
5482 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5483 worst_case_length);
5484 Object* new_object;
5485 if (!new_alloc->ToObject(&new_object)) {
5486 return new_alloc;
5487 }
5488 if (!isolate->heap()->new_space()->Contains(new_object)) {
5489 // Even if our string is small enough to fit in new space we still have to
5490 // handle it being allocated in old space as may happen in the third
5491 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5492 // CEntryStub::GenerateCore.
5493 return isolate->heap()->undefined_value();
5494 }
5495 AssertNoAllocation no_gc;
5496 StringType* new_string = StringType::cast(new_object);
5497 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5498
5499 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5500 Char* write_cursor = reinterpret_cast<Char*>(
5501 new_string->address() + SeqAsciiString::kHeaderSize);
5502 *(write_cursor++) = '[';
5503 for (int i = 0; i < length; i++) {
5504 if (i != 0) *(write_cursor++) = ',';
5505 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005506 String::FlatContent content = str->GetFlatContent();
5507 ASSERT(content.IsFlat());
5508 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005509 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5510 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005511 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005512 } else {
5513 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5514 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005515 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005516 }
5517 }
5518 *(write_cursor++) = ']';
5519
5520 int final_length = static_cast<int>(
5521 write_cursor - reinterpret_cast<Char*>(
5522 new_string->address() + SeqAsciiString::kHeaderSize));
5523 isolate->heap()->new_space()->
5524 template ShrinkStringAtAllocationBoundary<StringType>(
5525 new_string, final_length);
5526 return new_string;
5527}
5528
5529
5530RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5531 NoHandleAllocation ha;
5532 ASSERT(args.length() == 1);
5533 CONVERT_CHECKED(JSArray, array, args[0]);
5534
5535 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5536 FixedArray* elements = FixedArray::cast(array->elements());
5537 int n = elements->length();
5538 bool ascii = true;
5539 int total_length = 0;
5540
5541 for (int i = 0; i < n; i++) {
5542 Object* elt = elements->get(i);
5543 if (!elt->IsString()) return isolate->heap()->undefined_value();
5544 String* element = String::cast(elt);
5545 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5546 total_length += element->length();
5547 if (ascii && element->IsTwoByteRepresentation()) {
5548 ascii = false;
5549 }
5550 }
5551
5552 int worst_case_length =
5553 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5554 + total_length * kJsonQuoteWorstCaseBlowup;
5555
5556 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5557 return isolate->heap()->undefined_value();
5558 }
5559
5560 if (ascii) {
5561 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5562 elements,
5563 worst_case_length);
5564 } else {
5565 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5566 elements,
5567 worst_case_length);
5568 }
5569}
5570
5571
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005572RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005573 NoHandleAllocation ha;
5574
5575 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005576 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005577
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005578 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005579
lrn@chromium.org25156de2010-04-06 13:10:27 +00005580 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005581 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005582 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005583}
5584
5585
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005586RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005587 NoHandleAllocation ha;
5588 CONVERT_CHECKED(String, str, args[0]);
5589
5590 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005591 double value = StringToDouble(isolate->unicode_cache(),
5592 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005593
5594 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005595 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005596}
5597
5598
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005599template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005600MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005601 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005602 String* s,
5603 int length,
5604 int input_string_length,
5605 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005606 // We try this twice, once with the assumption that the result is no longer
5607 // than the input and, if that assumption breaks, again with the exact
5608 // length. This may not be pretty, but it is nicer than what was here before
5609 // and I hereby claim my vaffel-is.
5610 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005611 // Allocate the resulting string.
5612 //
5613 // NOTE: This assumes that the upper/lower case of an ascii
5614 // character is also ascii. This is currently the case, but it
5615 // might break in the future if we implement more context and locale
5616 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005617 Object* o;
5618 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005619 ? isolate->heap()->AllocateRawAsciiString(length)
5620 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005621 if (!maybe_o->ToObject(&o)) return maybe_o;
5622 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005623 String* result = String::cast(o);
5624 bool has_changed_character = false;
5625
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005626 // Convert all characters to upper case, assuming that they will fit
5627 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005628 Access<StringInputBuffer> buffer(
5629 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005630 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005631 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005632 // We can assume that the string is not empty
5633 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005634 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005635 bool has_next = buffer->has_more();
5636 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005637 int char_length = mapping->get(current, next, chars);
5638 if (char_length == 0) {
5639 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005640 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005641 i++;
5642 } else if (char_length == 1) {
5643 // Common case: converting the letter resulted in one character.
5644 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005645 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005646 has_changed_character = true;
5647 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005648 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005649 // We've assumed that the result would be as long as the
5650 // input but here is a character that converts to several
5651 // characters. No matter, we calculate the exact length
5652 // of the result and try the whole thing again.
5653 //
5654 // Note that this leaves room for optimization. We could just
5655 // memcpy what we already have to the result string. Also,
5656 // the result string is the last object allocated we could
5657 // "realloc" it and probably, in the vast majority of cases,
5658 // extend the existing string to be able to hold the full
5659 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005660 int next_length = 0;
5661 if (has_next) {
5662 next_length = mapping->get(next, 0, chars);
5663 if (next_length == 0) next_length = 1;
5664 }
5665 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005666 while (buffer->has_more()) {
5667 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005668 // NOTE: we use 0 as the next character here because, while
5669 // the next character may affect what a character converts to,
5670 // it does not in any case affect the length of what it convert
5671 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005672 int char_length = mapping->get(current, 0, chars);
5673 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005674 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005675 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005676 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005677 return Failure::OutOfMemoryException();
5678 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005679 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005680 // Try again with the real length.
5681 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005682 } else {
5683 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005684 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005685 i++;
5686 }
5687 has_changed_character = true;
5688 }
5689 current = next;
5690 }
5691 if (has_changed_character) {
5692 return result;
5693 } else {
5694 // If we didn't actually change anything in doing the conversion
5695 // we simple return the result and let the converted string
5696 // become garbage; there is no reason to keep two identical strings
5697 // alive.
5698 return s;
5699 }
5700}
5701
5702
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005703namespace {
5704
lrn@chromium.org303ada72010-10-27 09:33:13 +00005705static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5706
5707
5708// Given a word and two range boundaries returns a word with high bit
5709// set in every byte iff the corresponding input byte was strictly in
5710// the range (m, n). All the other bits in the result are cleared.
5711// This function is only useful when it can be inlined and the
5712// boundaries are statically known.
5713// Requires: all bytes in the input word and the boundaries must be
5714// ascii (less than 0x7F).
5715static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5716 // Every byte in an ascii string is less than or equal to 0x7F.
5717 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5718 // Use strict inequalities since in edge cases the function could be
5719 // further simplified.
5720 ASSERT(0 < m && m < n && n < 0x7F);
5721 // Has high bit set in every w byte less than n.
5722 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5723 // Has high bit set in every w byte greater than m.
5724 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5725 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5726}
5727
5728
5729enum AsciiCaseConversion {
5730 ASCII_TO_LOWER,
5731 ASCII_TO_UPPER
5732};
5733
5734
5735template <AsciiCaseConversion dir>
5736struct FastAsciiConverter {
5737 static bool Convert(char* dst, char* src, int length) {
5738#ifdef DEBUG
5739 char* saved_dst = dst;
5740 char* saved_src = src;
5741#endif
5742 // We rely on the distance between upper and lower case letters
5743 // being a known power of 2.
5744 ASSERT('a' - 'A' == (1 << 5));
5745 // Boundaries for the range of input characters than require conversion.
5746 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5747 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5748 bool changed = false;
5749 char* const limit = src + length;
5750#ifdef V8_HOST_CAN_READ_UNALIGNED
5751 // Process the prefix of the input that requires no conversion one
5752 // (machine) word at a time.
5753 while (src <= limit - sizeof(uintptr_t)) {
5754 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5755 if (AsciiRangeMask(w, lo, hi) != 0) {
5756 changed = true;
5757 break;
5758 }
5759 *reinterpret_cast<uintptr_t*>(dst) = w;
5760 src += sizeof(uintptr_t);
5761 dst += sizeof(uintptr_t);
5762 }
5763 // Process the remainder of the input performing conversion when
5764 // required one word at a time.
5765 while (src <= limit - sizeof(uintptr_t)) {
5766 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5767 uintptr_t m = AsciiRangeMask(w, lo, hi);
5768 // The mask has high (7th) bit set in every byte that needs
5769 // conversion and we know that the distance between cases is
5770 // 1 << 5.
5771 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5772 src += sizeof(uintptr_t);
5773 dst += sizeof(uintptr_t);
5774 }
5775#endif
5776 // Process the last few bytes of the input (or the whole input if
5777 // unaligned access is not supported).
5778 while (src < limit) {
5779 char c = *src;
5780 if (lo < c && c < hi) {
5781 c ^= (1 << 5);
5782 changed = true;
5783 }
5784 *dst = c;
5785 ++src;
5786 ++dst;
5787 }
5788#ifdef DEBUG
5789 CheckConvert(saved_dst, saved_src, length, changed);
5790#endif
5791 return changed;
5792 }
5793
5794#ifdef DEBUG
5795 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5796 bool expected_changed = false;
5797 for (int i = 0; i < length; i++) {
5798 if (dst[i] == src[i]) continue;
5799 expected_changed = true;
5800 if (dir == ASCII_TO_LOWER) {
5801 ASSERT('A' <= src[i] && src[i] <= 'Z');
5802 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5803 } else {
5804 ASSERT(dir == ASCII_TO_UPPER);
5805 ASSERT('a' <= src[i] && src[i] <= 'z');
5806 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5807 }
5808 }
5809 ASSERT(expected_changed == changed);
5810 }
5811#endif
5812};
5813
5814
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005815struct ToLowerTraits {
5816 typedef unibrow::ToLowercase UnibrowConverter;
5817
lrn@chromium.org303ada72010-10-27 09:33:13 +00005818 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005819};
5820
5821
5822struct ToUpperTraits {
5823 typedef unibrow::ToUppercase UnibrowConverter;
5824
lrn@chromium.org303ada72010-10-27 09:33:13 +00005825 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005826};
5827
5828} // namespace
5829
5830
5831template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005832MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005833 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005834 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005835 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005836 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005837 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005838 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005839
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005840 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005841 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005842 if (length == 0) return s;
5843
5844 // Simpler handling of ascii strings.
5845 //
5846 // NOTE: This assumes that the upper/lower case of an ascii
5847 // character is also ascii. This is currently the case, but it
5848 // might break in the future if we implement more context and locale
5849 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005850 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005851 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005852 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005853 if (!maybe_o->ToObject(&o)) return maybe_o;
5854 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005855 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005856 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005857 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005858 return has_changed_character ? result : s;
5859 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005860
lrn@chromium.org303ada72010-10-27 09:33:13 +00005861 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005862 { MaybeObject* maybe_answer =
5863 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005864 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5865 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005866 if (answer->IsSmi()) {
5867 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005868 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005869 ConvertCaseHelper(isolate,
5870 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005871 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5872 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005873 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005874 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005875}
5876
5877
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005878RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005879 return ConvertCase<ToLowerTraits>(
5880 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005881}
5882
5883
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005884RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005885 return ConvertCase<ToUpperTraits>(
5886 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005887}
5888
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005889
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005890static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5891 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5892}
5893
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005894
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005895RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005896 NoHandleAllocation ha;
5897 ASSERT(args.length() == 3);
5898
5899 CONVERT_CHECKED(String, s, args[0]);
5900 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5901 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5902
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005903 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005904 int length = s->length();
5905
5906 int left = 0;
5907 if (trimLeft) {
5908 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5909 left++;
5910 }
5911 }
5912
5913 int right = length;
5914 if (trimRight) {
5915 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5916 right--;
5917 }
5918 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005919 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005920}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005921
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005922
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005923void FindAsciiStringIndices(Vector<const char> subject,
5924 char pattern,
5925 ZoneList<int>* indices,
5926 unsigned int limit) {
5927 ASSERT(limit > 0);
5928 // Collect indices of pattern in subject using memchr.
5929 // Stop after finding at most limit values.
5930 const char* subject_start = reinterpret_cast<const char*>(subject.start());
5931 const char* subject_end = subject_start + subject.length();
5932 const char* pos = subject_start;
5933 while (limit > 0) {
5934 pos = reinterpret_cast<const char*>(
5935 memchr(pos, pattern, subject_end - pos));
5936 if (pos == NULL) return;
5937 indices->Add(static_cast<int>(pos - subject_start));
5938 pos++;
5939 limit--;
5940 }
5941}
5942
5943
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005944template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005945void FindStringIndices(Isolate* isolate,
5946 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005947 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005948 ZoneList<int>* indices,
5949 unsigned int limit) {
5950 ASSERT(limit > 0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005951 // Collect indices of pattern in subject.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005952 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005953 int pattern_length = pattern.length();
5954 int index = 0;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005955 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005956 while (limit > 0) {
5957 index = search.Search(subject, index);
5958 if (index < 0) return;
5959 indices->Add(index);
5960 index += pattern_length;
5961 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005962 }
5963}
5964
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005966RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005967 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005968 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005969 CONVERT_ARG_CHECKED(String, subject, 0);
5970 CONVERT_ARG_CHECKED(String, pattern, 1);
5971 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5972
5973 int subject_length = subject->length();
5974 int pattern_length = pattern->length();
5975 RUNTIME_ASSERT(pattern_length > 0);
5976
5977 // The limit can be very large (0xffffffffu), but since the pattern
5978 // isn't empty, we can never create more parts than ~half the length
5979 // of the subject.
5980
5981 if (!subject->IsFlat()) FlattenString(subject);
5982
5983 static const int kMaxInitialListCapacity = 16;
5984
danno@chromium.org40cb8782011-05-25 07:58:50 +00005985 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005986
5987 // Find (up to limit) indices of separator and end-of-string in subject
5988 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5989 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005990 if (!pattern->IsFlat()) FlattenString(pattern);
5991
5992 // No allocation block.
5993 {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005994 AssertNoAllocation no_gc;
5995 String::FlatContent subject_content = subject->GetFlatContent();
5996 String::FlatContent pattern_content = pattern->GetFlatContent();
5997 ASSERT(subject_content.IsFlat());
5998 ASSERT(pattern_content.IsFlat());
5999 if (subject_content.IsAscii()) {
6000 Vector<const char> subject_vector = subject_content.ToAsciiVector();
6001 if (pattern_content.IsAscii()) {
6002 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00006003 if (pattern_vector.length() == 1) {
6004 FindAsciiStringIndices(subject_vector,
6005 pattern_vector[0],
6006 &indices,
6007 limit);
6008 } else {
6009 FindStringIndices(isolate,
6010 subject_vector,
6011 pattern_vector,
6012 &indices,
6013 limit);
6014 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006015 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006016 FindStringIndices(isolate,
6017 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006018 pattern_content.ToUC16Vector(),
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006019 &indices,
6020 limit);
6021 }
6022 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006023 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006024 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006025 FindStringIndices(isolate,
6026 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006027 pattern_content.ToAsciiVector(),
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006028 &indices,
6029 limit);
6030 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006031 FindStringIndices(isolate,
6032 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006033 pattern_content.ToUC16Vector(),
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006034 &indices,
6035 limit);
6036 }
6037 }
6038 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006039
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006040 if (static_cast<uint32_t>(indices.length()) < limit) {
6041 indices.Add(subject_length);
6042 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006043
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006044 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006045
6046 // Create JSArray of substrings separated by separator.
6047 int part_count = indices.length();
6048
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006049 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006050 result->set_length(Smi::FromInt(part_count));
6051
6052 ASSERT(result->HasFastElements());
6053
6054 if (part_count == 1 && indices.at(0) == subject_length) {
6055 FixedArray::cast(result->elements())->set(0, *subject);
6056 return *result;
6057 }
6058
6059 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6060 int part_start = 0;
6061 for (int i = 0; i < part_count; i++) {
6062 HandleScope local_loop_handle;
6063 int part_end = indices.at(i);
6064 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006065 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006066 elements->set(i, *substring);
6067 part_start = part_end + pattern_length;
6068 }
6069
6070 return *result;
6071}
6072
6073
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006074// Copies ascii characters to the given fixed array looking up
6075// one-char strings in the cache. Gives up on the first char that is
6076// not in the cache and fills the remainder with smi zeros. Returns
6077// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006078static int CopyCachedAsciiCharsToArray(Heap* heap,
6079 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006080 FixedArray* elements,
6081 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006082 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006083 FixedArray* ascii_cache = heap->single_character_string_cache();
6084 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006085 int i;
6086 for (i = 0; i < length; ++i) {
6087 Object* value = ascii_cache->get(chars[i]);
6088 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006089 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006090 elements->set(i, value, SKIP_WRITE_BARRIER);
6091 }
6092 if (i < length) {
6093 ASSERT(Smi::FromInt(0) == 0);
6094 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6095 }
6096#ifdef DEBUG
6097 for (int j = 0; j < length; ++j) {
6098 Object* element = elements->get(j);
6099 ASSERT(element == Smi::FromInt(0) ||
6100 (element->IsString() && String::cast(element)->LooksValid()));
6101 }
6102#endif
6103 return i;
6104}
6105
6106
6107// Converts a String to JSArray.
6108// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006109RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006110 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006111 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006112 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006113 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006114
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006115 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006116 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006117
6118 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006119 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006120 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006121 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006122 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006123 { MaybeObject* maybe_obj =
6124 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006125 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6126 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006127 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006128 String::FlatContent content = s->GetFlatContent();
6129 if (content.IsAscii()) {
6130 Vector<const char> chars = content.ToAsciiVector();
6131 // Note, this will initialize all elements (not only the prefix)
6132 // to prevent GC from seeing partially initialized array.
6133 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6134 chars.start(),
6135 *elements,
6136 length);
6137 } else {
6138 MemsetPointer(elements->data_start(),
6139 isolate->heap()->undefined_value(),
6140 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006141 }
6142 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006143 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006144 }
6145 for (int i = position; i < length; ++i) {
6146 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6147 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006148 }
6149
6150#ifdef DEBUG
6151 for (int i = 0; i < length; ++i) {
6152 ASSERT(String::cast(elements->get(i))->length() == 1);
6153 }
6154#endif
6155
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006156 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006157}
6158
6159
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006160RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006161 NoHandleAllocation ha;
6162 ASSERT(args.length() == 1);
6163 CONVERT_CHECKED(String, value, args[0]);
6164 return value->ToObject();
6165}
6166
6167
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006168bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006169 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006170 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006171 return char_length == 0;
6172}
6173
6174
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006175RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006176 NoHandleAllocation ha;
6177 ASSERT(args.length() == 1);
6178
6179 Object* number = args[0];
6180 RUNTIME_ASSERT(number->IsNumber());
6181
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006182 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006183}
6184
6185
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006186RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006187 NoHandleAllocation ha;
6188 ASSERT(args.length() == 1);
6189
6190 Object* number = args[0];
6191 RUNTIME_ASSERT(number->IsNumber());
6192
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006193 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006194}
6195
6196
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006197RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006198 NoHandleAllocation ha;
6199 ASSERT(args.length() == 1);
6200
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006201 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006202
6203 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6204 if (number > 0 && number <= Smi::kMaxValue) {
6205 return Smi::FromInt(static_cast<int>(number));
6206 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006207 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006208}
6209
6210
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006211RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006212 NoHandleAllocation ha;
6213 ASSERT(args.length() == 1);
6214
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006215 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006216
6217 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6218 if (number > 0 && number <= Smi::kMaxValue) {
6219 return Smi::FromInt(static_cast<int>(number));
6220 }
6221
6222 double double_value = DoubleToInteger(number);
6223 // Map both -0 and +0 to +0.
6224 if (double_value == 0) double_value = 0;
6225
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006226 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006227}
6228
6229
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006230RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006231 NoHandleAllocation ha;
6232 ASSERT(args.length() == 1);
6233
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006234 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006235 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006236}
6237
6238
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006239RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006240 NoHandleAllocation ha;
6241 ASSERT(args.length() == 1);
6242
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006243 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006244
6245 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6246 if (number > 0 && number <= Smi::kMaxValue) {
6247 return Smi::FromInt(static_cast<int>(number));
6248 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006249 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006250}
6251
6252
ager@chromium.org870a0b62008-11-04 11:43:05 +00006253// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6254// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006255RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006256 NoHandleAllocation ha;
6257 ASSERT(args.length() == 1);
6258
6259 Object* obj = args[0];
6260 if (obj->IsSmi()) {
6261 return obj;
6262 }
6263 if (obj->IsHeapNumber()) {
6264 double value = HeapNumber::cast(obj)->value();
6265 int int_value = FastD2I(value);
6266 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6267 return Smi::FromInt(int_value);
6268 }
6269 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006270 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006271}
6272
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006273
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006274RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006275 NoHandleAllocation ha;
6276 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006277 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006278}
6279
6280
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006281RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006282 NoHandleAllocation ha;
6283 ASSERT(args.length() == 2);
6284
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006285 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6286 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006287 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006288}
6289
6290
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006291RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006292 NoHandleAllocation ha;
6293 ASSERT(args.length() == 2);
6294
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006295 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6296 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006297 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006298}
6299
6300
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006301RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006302 NoHandleAllocation ha;
6303 ASSERT(args.length() == 2);
6304
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006305 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6306 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006307 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006308}
6309
6310
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006311RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006312 NoHandleAllocation ha;
6313 ASSERT(args.length() == 1);
6314
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006315 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006316 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006317}
6318
6319
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006320RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006321 NoHandleAllocation ha;
6322 ASSERT(args.length() == 0);
6323
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006324 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006325}
6326
6327
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006328RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006329 NoHandleAllocation ha;
6330 ASSERT(args.length() == 2);
6331
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006332 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6333 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006334 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006335}
6336
6337
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006338RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006339 NoHandleAllocation ha;
6340 ASSERT(args.length() == 2);
6341
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006342 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6343 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006344
ager@chromium.org3811b432009-10-28 14:53:37 +00006345 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006346 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006347 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006348}
6349
6350
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006351RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006352 NoHandleAllocation ha;
6353 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006354 CONVERT_CHECKED(String, str1, args[0]);
6355 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006356 isolate->counters()->string_add_runtime()->Increment();
6357 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006358}
6359
6360
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006361template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006362static inline void StringBuilderConcatHelper(String* special,
6363 sinkchar* sink,
6364 FixedArray* fixed_array,
6365 int array_length) {
6366 int position = 0;
6367 for (int i = 0; i < array_length; i++) {
6368 Object* element = fixed_array->get(i);
6369 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006370 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006371 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006372 int pos;
6373 int len;
6374 if (encoded_slice > 0) {
6375 // Position and length encoded in one smi.
6376 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6377 len = StringBuilderSubstringLength::decode(encoded_slice);
6378 } else {
6379 // Position and length encoded in two smis.
6380 Object* obj = fixed_array->get(++i);
6381 ASSERT(obj->IsSmi());
6382 pos = Smi::cast(obj)->value();
6383 len = -encoded_slice;
6384 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006385 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006386 sink + position,
6387 pos,
6388 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006389 position += len;
6390 } else {
6391 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006392 int element_length = string->length();
6393 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006394 position += element_length;
6395 }
6396 }
6397}
6398
6399
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006400RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006401 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006402 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006403 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006404 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006405 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006406 return Failure::OutOfMemoryException();
6407 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006408 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006409 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006410
6411 // This assumption is used by the slice encoding in one or two smis.
6412 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6413
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006414 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006415 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006416 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006417 }
6418 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006419 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006420 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006421 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006422
6423 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006424 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006425 } else if (array_length == 1) {
6426 Object* first = fixed_array->get(0);
6427 if (first->IsString()) return first;
6428 }
6429
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006430 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006431 int position = 0;
6432 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006433 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006434 Object* elt = fixed_array->get(i);
6435 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006436 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006437 int smi_value = Smi::cast(elt)->value();
6438 int pos;
6439 int len;
6440 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006441 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006442 pos = StringBuilderSubstringPosition::decode(smi_value);
6443 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006444 } else {
6445 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006446 len = -smi_value;
6447 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006448 i++;
6449 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006450 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006451 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006452 Object* next_smi = fixed_array->get(i);
6453 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006454 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006455 }
6456 pos = Smi::cast(next_smi)->value();
6457 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006458 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006459 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006460 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006461 ASSERT(pos >= 0);
6462 ASSERT(len >= 0);
6463 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006464 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006465 }
6466 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006467 } else if (elt->IsString()) {
6468 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006469 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006470 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006471 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006472 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006473 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006474 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006475 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006476 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006477 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006478 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006479 return Failure::OutOfMemoryException();
6480 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006481 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006482 }
6483
6484 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006485 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006486
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006487 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006488 { MaybeObject* maybe_object =
6489 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006490 if (!maybe_object->ToObject(&object)) return maybe_object;
6491 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006492 SeqAsciiString* answer = SeqAsciiString::cast(object);
6493 StringBuilderConcatHelper(special,
6494 answer->GetChars(),
6495 fixed_array,
6496 array_length);
6497 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006498 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006499 { MaybeObject* maybe_object =
6500 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006501 if (!maybe_object->ToObject(&object)) return maybe_object;
6502 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006503 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6504 StringBuilderConcatHelper(special,
6505 answer->GetChars(),
6506 fixed_array,
6507 array_length);
6508 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006509 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006510}
6511
6512
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006513RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006514 NoHandleAllocation ha;
6515 ASSERT(args.length() == 3);
6516 CONVERT_CHECKED(JSArray, array, args[0]);
6517 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006518 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006519 return Failure::OutOfMemoryException();
6520 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006521 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006522 CONVERT_CHECKED(String, separator, args[2]);
6523
6524 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006525 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006526 }
6527 FixedArray* fixed_array = FixedArray::cast(array->elements());
6528 if (fixed_array->length() < array_length) {
6529 array_length = fixed_array->length();
6530 }
6531
6532 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006533 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006534 } else if (array_length == 1) {
6535 Object* first = fixed_array->get(0);
6536 if (first->IsString()) return first;
6537 }
6538
6539 int separator_length = separator->length();
6540 int max_nof_separators =
6541 (String::kMaxLength + separator_length - 1) / separator_length;
6542 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006543 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006544 return Failure::OutOfMemoryException();
6545 }
6546 int length = (array_length - 1) * separator_length;
6547 for (int i = 0; i < array_length; i++) {
6548 Object* element_obj = fixed_array->get(i);
6549 if (!element_obj->IsString()) {
6550 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006551 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006552 }
6553 String* element = String::cast(element_obj);
6554 int increment = element->length();
6555 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006556 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006557 return Failure::OutOfMemoryException();
6558 }
6559 length += increment;
6560 }
6561
6562 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006563 { MaybeObject* maybe_object =
6564 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006565 if (!maybe_object->ToObject(&object)) return maybe_object;
6566 }
6567 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6568
6569 uc16* sink = answer->GetChars();
6570#ifdef DEBUG
6571 uc16* end = sink + length;
6572#endif
6573
6574 String* first = String::cast(fixed_array->get(0));
6575 int first_length = first->length();
6576 String::WriteToFlat(first, sink, 0, first_length);
6577 sink += first_length;
6578
6579 for (int i = 1; i < array_length; i++) {
6580 ASSERT(sink + separator_length <= end);
6581 String::WriteToFlat(separator, sink, 0, separator_length);
6582 sink += separator_length;
6583
6584 String* element = String::cast(fixed_array->get(i));
6585 int element_length = element->length();
6586 ASSERT(sink + element_length <= end);
6587 String::WriteToFlat(element, sink, 0, element_length);
6588 sink += element_length;
6589 }
6590 ASSERT(sink == end);
6591
6592 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6593 return answer;
6594}
6595
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006596template <typename Char>
6597static void JoinSparseArrayWithSeparator(FixedArray* elements,
6598 int elements_length,
6599 uint32_t array_length,
6600 String* separator,
6601 Vector<Char> buffer) {
6602 int previous_separator_position = 0;
6603 int separator_length = separator->length();
6604 int cursor = 0;
6605 for (int i = 0; i < elements_length; i += 2) {
6606 int position = NumberToInt32(elements->get(i));
6607 String* string = String::cast(elements->get(i + 1));
6608 int string_length = string->length();
6609 if (string->length() > 0) {
6610 while (previous_separator_position < position) {
6611 String::WriteToFlat<Char>(separator, &buffer[cursor],
6612 0, separator_length);
6613 cursor += separator_length;
6614 previous_separator_position++;
6615 }
6616 String::WriteToFlat<Char>(string, &buffer[cursor],
6617 0, string_length);
6618 cursor += string->length();
6619 }
6620 }
6621 if (separator_length > 0) {
6622 // Array length must be representable as a signed 32-bit number,
6623 // otherwise the total string length would have been too large.
6624 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6625 int last_array_index = static_cast<int>(array_length - 1);
6626 while (previous_separator_position < last_array_index) {
6627 String::WriteToFlat<Char>(separator, &buffer[cursor],
6628 0, separator_length);
6629 cursor += separator_length;
6630 previous_separator_position++;
6631 }
6632 }
6633 ASSERT(cursor <= buffer.length());
6634}
6635
6636
6637RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6638 NoHandleAllocation ha;
6639 ASSERT(args.length() == 3);
6640 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6641 RUNTIME_ASSERT(elements_array->HasFastElements());
6642 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6643 CONVERT_CHECKED(String, separator, args[2]);
6644 // elements_array is fast-mode JSarray of alternating positions
6645 // (increasing order) and strings.
6646 // array_length is length of original array (used to add separators);
6647 // separator is string to put between elements. Assumed to be non-empty.
6648
6649 // Find total length of join result.
6650 int string_length = 0;
6651 bool is_ascii = true;
6652 int max_string_length = SeqAsciiString::kMaxLength;
6653 bool overflow = false;
6654 CONVERT_NUMBER_CHECKED(int, elements_length,
6655 Int32, elements_array->length());
6656 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6657 FixedArray* elements = FixedArray::cast(elements_array->elements());
6658 for (int i = 0; i < elements_length; i += 2) {
6659 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6660 CONVERT_CHECKED(String, string, elements->get(i + 1));
6661 int length = string->length();
6662 if (is_ascii && !string->IsAsciiRepresentation()) {
6663 is_ascii = false;
6664 max_string_length = SeqTwoByteString::kMaxLength;
6665 }
6666 if (length > max_string_length ||
6667 max_string_length - length < string_length) {
6668 overflow = true;
6669 break;
6670 }
6671 string_length += length;
6672 }
6673 int separator_length = separator->length();
6674 if (!overflow && separator_length > 0) {
6675 if (array_length <= 0x7fffffffu) {
6676 int separator_count = static_cast<int>(array_length) - 1;
6677 int remaining_length = max_string_length - string_length;
6678 if ((remaining_length / separator_length) >= separator_count) {
6679 string_length += separator_length * (array_length - 1);
6680 } else {
6681 // Not room for the separators within the maximal string length.
6682 overflow = true;
6683 }
6684 } else {
6685 // Nonempty separator and at least 2^31-1 separators necessary
6686 // means that the string is too large to create.
6687 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6688 overflow = true;
6689 }
6690 }
6691 if (overflow) {
6692 // Throw OutOfMemory exception for creating too large a string.
6693 V8::FatalProcessOutOfMemory("Array join result too large.");
6694 }
6695
6696 if (is_ascii) {
6697 MaybeObject* result_allocation =
6698 isolate->heap()->AllocateRawAsciiString(string_length);
6699 if (result_allocation->IsFailure()) return result_allocation;
6700 SeqAsciiString* result_string =
6701 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6702 JoinSparseArrayWithSeparator<char>(elements,
6703 elements_length,
6704 array_length,
6705 separator,
6706 Vector<char>(result_string->GetChars(),
6707 string_length));
6708 return result_string;
6709 } else {
6710 MaybeObject* result_allocation =
6711 isolate->heap()->AllocateRawTwoByteString(string_length);
6712 if (result_allocation->IsFailure()) return result_allocation;
6713 SeqTwoByteString* result_string =
6714 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6715 JoinSparseArrayWithSeparator<uc16>(elements,
6716 elements_length,
6717 array_length,
6718 separator,
6719 Vector<uc16>(result_string->GetChars(),
6720 string_length));
6721 return result_string;
6722 }
6723}
6724
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006725
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006726RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006727 NoHandleAllocation ha;
6728 ASSERT(args.length() == 2);
6729
6730 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6731 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006732 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006733}
6734
6735
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006736RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006737 NoHandleAllocation ha;
6738 ASSERT(args.length() == 2);
6739
6740 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6741 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006742 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006743}
6744
6745
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006746RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
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);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006753}
6754
6755
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006756RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006757 NoHandleAllocation ha;
6758 ASSERT(args.length() == 1);
6759
6760 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006761 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006762}
6763
6764
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006765RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006766 NoHandleAllocation ha;
6767 ASSERT(args.length() == 2);
6768
6769 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6770 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006771 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006772}
6773
6774
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006775RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006776 NoHandleAllocation ha;
6777 ASSERT(args.length() == 2);
6778
6779 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6780 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006781 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006782}
6783
6784
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006785RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006786 NoHandleAllocation ha;
6787 ASSERT(args.length() == 2);
6788
6789 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6790 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006791 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006792}
6793
6794
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006795RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006796 NoHandleAllocation ha;
6797 ASSERT(args.length() == 2);
6798
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006799 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6800 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006801 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6802 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6803 if (x == y) return Smi::FromInt(EQUAL);
6804 Object* result;
6805 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6806 result = Smi::FromInt(EQUAL);
6807 } else {
6808 result = Smi::FromInt(NOT_EQUAL);
6809 }
6810 return result;
6811}
6812
6813
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006814RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006815 NoHandleAllocation ha;
6816 ASSERT(args.length() == 2);
6817
6818 CONVERT_CHECKED(String, x, args[0]);
6819 CONVERT_CHECKED(String, y, args[1]);
6820
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006821 bool not_equal = !x->Equals(y);
6822 // This is slightly convoluted because the value that signifies
6823 // equality is 0 and inequality is 1 so we have to negate the result
6824 // from String::Equals.
6825 ASSERT(not_equal == 0 || not_equal == 1);
6826 STATIC_CHECK(EQUAL == 0);
6827 STATIC_CHECK(NOT_EQUAL == 1);
6828 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006829}
6830
6831
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006832RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006833 NoHandleAllocation ha;
6834 ASSERT(args.length() == 3);
6835
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006836 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6837 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006838 if (isnan(x) || isnan(y)) return args[2];
6839 if (x == y) return Smi::FromInt(EQUAL);
6840 if (isless(x, y)) return Smi::FromInt(LESS);
6841 return Smi::FromInt(GREATER);
6842}
6843
6844
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006845// Compare two Smis as if they were converted to strings and then
6846// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006847RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006848 NoHandleAllocation ha;
6849 ASSERT(args.length() == 2);
6850
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006851 // Extract the integer values from the Smis.
6852 CONVERT_CHECKED(Smi, x, args[0]);
6853 CONVERT_CHECKED(Smi, y, args[1]);
6854 int x_value = x->value();
6855 int y_value = y->value();
6856
6857 // If the integers are equal so are the string representations.
6858 if (x_value == y_value) return Smi::FromInt(EQUAL);
6859
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006860 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006861 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006862 if (x_value == 0 || y_value == 0)
6863 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006864
ager@chromium.org32912102009-01-16 10:38:43 +00006865 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006866 // smallest because the char code of '-' is less than the char code
6867 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006868
6869 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
6870 // architectures using 32-bit Smis.
6871 uint32_t x_scaled = x_value;
6872 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006873 if (x_value < 0 || y_value < 0) {
6874 if (y_value >= 0) return Smi::FromInt(LESS);
6875 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006876 x_scaled = -x_value;
6877 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006878 }
6879
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006880 static const uint32_t kPowersOf10[] = {
6881 1, 10, 100, 1000, 10*1000, 100*1000,
6882 1000*1000, 10*1000*1000, 100*1000*1000,
6883 1000*1000*1000
6884 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006885
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006886 // If the integers have the same number of decimal digits they can be
6887 // compared directly as the numeric order is the same as the
6888 // lexicographic order. If one integer has fewer digits, it is scaled
6889 // by some power of 10 to have the same number of digits as the longer
6890 // integer. If the scaled integers are equal it means the shorter
6891 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006892
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006893 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
6894 int x_log2 = IntegerLog2(x_scaled);
6895 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
6896 x_log10 -= x_scaled < kPowersOf10[x_log10];
6897
6898 int y_log2 = IntegerLog2(y_scaled);
6899 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
6900 y_log10 -= y_scaled < kPowersOf10[y_log10];
6901
6902 int tie = EQUAL;
6903
6904 if (x_log10 < y_log10) {
6905 // X has fewer digits. We would like to simply scale up X but that
6906 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
6907 // be scaled up to 9_000_000_000. So we scale up by the next
6908 // smallest power and scale down Y to drop one digit. It is OK to
6909 // drop one digit from the longer integer since the final digit is
6910 // past the length of the shorter integer.
6911 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
6912 y_scaled /= 10;
6913 tie = LESS;
6914 } else if (y_log10 < x_log10) {
6915 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
6916 x_scaled /= 10;
6917 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006918 }
6919
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006920 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
6921 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
6922 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006923}
6924
6925
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006926static Object* StringInputBufferCompare(RuntimeState* state,
6927 String* x,
6928 String* y) {
6929 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6930 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006931 bufx.Reset(x);
6932 bufy.Reset(y);
6933 while (bufx.has_more() && bufy.has_more()) {
6934 int d = bufx.GetNext() - bufy.GetNext();
6935 if (d < 0) return Smi::FromInt(LESS);
6936 else if (d > 0) return Smi::FromInt(GREATER);
6937 }
6938
6939 // x is (non-trivial) prefix of y:
6940 if (bufy.has_more()) return Smi::FromInt(LESS);
6941 // y is prefix of x:
6942 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6943}
6944
6945
6946static Object* FlatStringCompare(String* x, String* y) {
6947 ASSERT(x->IsFlat());
6948 ASSERT(y->IsFlat());
6949 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6950 int prefix_length = x->length();
6951 if (y->length() < prefix_length) {
6952 prefix_length = y->length();
6953 equal_prefix_result = Smi::FromInt(GREATER);
6954 } else if (y->length() > prefix_length) {
6955 equal_prefix_result = Smi::FromInt(LESS);
6956 }
6957 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006958 String::FlatContent x_content = x->GetFlatContent();
6959 String::FlatContent y_content = y->GetFlatContent();
6960 if (x_content.IsAscii()) {
6961 Vector<const char> x_chars = x_content.ToAsciiVector();
6962 if (y_content.IsAscii()) {
6963 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006964 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006965 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006966 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006967 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6968 }
6969 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006970 Vector<const uc16> x_chars = x_content.ToUC16Vector();
6971 if (y_content.IsAscii()) {
6972 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006973 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6974 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006975 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006976 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6977 }
6978 }
6979 Object* result;
6980 if (r == 0) {
6981 result = equal_prefix_result;
6982 } else {
6983 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6984 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006985 ASSERT(result ==
6986 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006987 return result;
6988}
6989
6990
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006991RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006992 NoHandleAllocation ha;
6993 ASSERT(args.length() == 2);
6994
6995 CONVERT_CHECKED(String, x, args[0]);
6996 CONVERT_CHECKED(String, y, args[1]);
6997
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006998 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006999
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007000 // A few fast case tests before we flatten.
7001 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007002 if (y->length() == 0) {
7003 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007004 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007005 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007006 return Smi::FromInt(LESS);
7007 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007008
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007009 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007010 if (d < 0) return Smi::FromInt(LESS);
7011 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007012
lrn@chromium.org303ada72010-10-27 09:33:13 +00007013 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007014 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007015 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7016 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007017 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007018 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7019 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007020
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007021 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007022 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007023}
7024
7025
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007026RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007027 NoHandleAllocation ha;
7028 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007029 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007030
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007031 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007032 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007033}
7034
7035
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007036RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007037 NoHandleAllocation ha;
7038 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007039 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007040
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007041 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007042 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007043}
7044
7045
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007046RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007047 NoHandleAllocation ha;
7048 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007049 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007050
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007051 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007052 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007053}
7054
7055
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007056static const double kPiDividedBy4 = 0.78539816339744830962;
7057
7058
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007059RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007060 NoHandleAllocation ha;
7061 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007062 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007063
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007064 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7065 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007066 double result;
7067 if (isinf(x) && isinf(y)) {
7068 // Make sure that the result in case of two infinite arguments
7069 // is a multiple of Pi / 4. The sign of the result is determined
7070 // by the first argument (x) and the sign of the second argument
7071 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007072 int multiplier = (x < 0) ? -1 : 1;
7073 if (y < 0) multiplier *= 3;
7074 result = multiplier * kPiDividedBy4;
7075 } else {
7076 result = atan2(x, y);
7077 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007078 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007079}
7080
7081
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007082RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007083 NoHandleAllocation ha;
7084 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007085 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007086
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007087 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007088 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007089}
7090
7091
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007092RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007093 NoHandleAllocation ha;
7094 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007095 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007096
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007097 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007098 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007099}
7100
7101
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007102RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007103 NoHandleAllocation ha;
7104 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007105 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007106
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007107 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007108 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007109}
7110
7111
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007112RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007113 NoHandleAllocation ha;
7114 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007115 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007116
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007117 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007118 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007119}
7120
7121
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007122RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007123 NoHandleAllocation ha;
7124 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007125 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007126
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007127 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007128 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007129}
7130
7131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007132RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007133 NoHandleAllocation ha;
7134 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007135 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007136
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007137 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007138
7139 // If the second argument is a smi, it is much faster to call the
7140 // custom powi() function than the generic pow().
7141 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007142 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007143 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007144 }
7145
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007146 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007147 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007148}
7149
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007150// Fast version of Math.pow if we know that y is not an integer and
7151// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007152RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007153 NoHandleAllocation ha;
7154 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007155 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7156 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007157 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007158 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007159 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007160 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007161 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007162 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007163 }
7164}
7165
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007166
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007167RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007168 NoHandleAllocation ha;
7169 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007170 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007171
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007172 if (!args[0]->IsHeapNumber()) {
7173 // Must be smi. Return the argument unchanged for all the other types
7174 // to make fuzz-natives test happy.
7175 return args[0];
7176 }
7177
7178 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7179
7180 double value = number->value();
7181 int exponent = number->get_exponent();
7182 int sign = number->get_sign();
7183
danno@chromium.org160a7b02011-04-18 15:51:38 +00007184 if (exponent < -1) {
7185 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7186 if (sign) return isolate->heap()->minus_zero_value();
7187 return Smi::FromInt(0);
7188 }
7189
7190 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7191 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7192 // agument holds for 32-bit smis).
7193 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007194 return Smi::FromInt(static_cast<int>(value + 0.5));
7195 }
7196
7197 // If the magnitude is big enough, there's no place for fraction part. If we
7198 // try to add 0.5 to this number, 1.0 will be added instead.
7199 if (exponent >= 52) {
7200 return number;
7201 }
7202
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007203 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007204
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007205 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007206 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007207}
7208
7209
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007210RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007211 NoHandleAllocation ha;
7212 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007213 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007214
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007215 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007216 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007217}
7218
7219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007220RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007221 NoHandleAllocation ha;
7222 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007223 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007224
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007225 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007226 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007227}
7228
7229
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007230RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007231 NoHandleAllocation ha;
7232 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007233 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007234
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007235 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007236 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007237}
7238
7239
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007240static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007241 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7242 181, 212, 243, 273, 304, 334};
7243 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7244 182, 213, 244, 274, 305, 335};
7245
7246 year += month / 12;
7247 month %= 12;
7248 if (month < 0) {
7249 year--;
7250 month += 12;
7251 }
7252
7253 ASSERT(month >= 0);
7254 ASSERT(month < 12);
7255
7256 // year_delta is an arbitrary number such that:
7257 // a) year_delta = -1 (mod 400)
7258 // b) year + year_delta > 0 for years in the range defined by
7259 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7260 // Jan 1 1970. This is required so that we don't run into integer
7261 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007262 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007263 // operations.
7264 static const int year_delta = 399999;
7265 static const int base_day = 365 * (1970 + year_delta) +
7266 (1970 + year_delta) / 4 -
7267 (1970 + year_delta) / 100 +
7268 (1970 + year_delta) / 400;
7269
7270 int year1 = year + year_delta;
7271 int day_from_year = 365 * year1 +
7272 year1 / 4 -
7273 year1 / 100 +
7274 year1 / 400 -
7275 base_day;
7276
7277 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007278 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007279 }
7280
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007281 return day_from_year + day_from_month_leap[month] + day - 1;
7282}
7283
7284
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007285RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007286 NoHandleAllocation ha;
7287 ASSERT(args.length() == 3);
7288
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007289 CONVERT_SMI_ARG_CHECKED(year, 0);
7290 CONVERT_SMI_ARG_CHECKED(month, 1);
7291 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007292
7293 return Smi::FromInt(MakeDay(year, month, date));
7294}
7295
7296
7297static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7298static const int kDaysIn4Years = 4 * 365 + 1;
7299static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7300static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7301static const int kDays1970to2000 = 30 * 365 + 7;
7302static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7303 kDays1970to2000;
7304static const int kYearsOffset = 400000;
7305
7306static const char kDayInYear[] = {
7307 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7308 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7309 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7310 22, 23, 24, 25, 26, 27, 28,
7311 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7312 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
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,
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, 29, 30, 31,
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,
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, 31,
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,
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, 31,
7331
7332 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7333 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7334 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7335 22, 23, 24, 25, 26, 27, 28,
7336 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7337 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
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,
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, 30, 31,
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,
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, 31,
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,
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, 31,
7356
7357 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7358 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7359 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7360 22, 23, 24, 25, 26, 27, 28, 29,
7361 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7362 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
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,
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, 29, 30, 31,
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,
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, 31,
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,
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, 31,
7381
7382 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7383 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7384 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7385 22, 23, 24, 25, 26, 27, 28,
7386 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7387 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7388 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7389 22, 23, 24, 25, 26, 27, 28, 29, 30,
7390 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7391 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7392 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7393 22, 23, 24, 25, 26, 27, 28, 29, 30,
7394 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7395 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7396 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7397 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7398 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7399 22, 23, 24, 25, 26, 27, 28, 29, 30,
7400 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7401 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7402 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7403 22, 23, 24, 25, 26, 27, 28, 29, 30,
7404 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7405 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7406
7407static const char kMonthInYear[] = {
7408 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,
7409 0, 0, 0, 0, 0, 0,
7410 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,
7411 1, 1, 1,
7412 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,
7413 2, 2, 2, 2, 2, 2,
7414 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,
7415 3, 3, 3, 3, 3,
7416 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,
7417 4, 4, 4, 4, 4, 4,
7418 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,
7419 5, 5, 5, 5, 5,
7420 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,
7421 6, 6, 6, 6, 6, 6,
7422 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,
7423 7, 7, 7, 7, 7, 7,
7424 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,
7425 8, 8, 8, 8, 8,
7426 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,
7427 9, 9, 9, 9, 9, 9,
7428 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7429 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7430 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7431 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7432
7433 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,
7434 0, 0, 0, 0, 0, 0,
7435 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,
7436 1, 1, 1,
7437 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,
7438 2, 2, 2, 2, 2, 2,
7439 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,
7440 3, 3, 3, 3, 3,
7441 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,
7442 4, 4, 4, 4, 4, 4,
7443 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,
7444 5, 5, 5, 5, 5,
7445 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,
7446 6, 6, 6, 6, 6, 6,
7447 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,
7448 7, 7, 7, 7, 7, 7,
7449 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,
7450 8, 8, 8, 8, 8,
7451 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,
7452 9, 9, 9, 9, 9, 9,
7453 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7454 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7455 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7456 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7457
7458 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,
7459 0, 0, 0, 0, 0, 0,
7460 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,
7461 1, 1, 1, 1,
7462 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,
7463 2, 2, 2, 2, 2, 2,
7464 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,
7465 3, 3, 3, 3, 3,
7466 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,
7467 4, 4, 4, 4, 4, 4,
7468 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,
7469 5, 5, 5, 5, 5,
7470 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,
7471 6, 6, 6, 6, 6, 6,
7472 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,
7473 7, 7, 7, 7, 7, 7,
7474 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,
7475 8, 8, 8, 8, 8,
7476 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,
7477 9, 9, 9, 9, 9, 9,
7478 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7479 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7480 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7481 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7482
7483 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,
7484 0, 0, 0, 0, 0, 0,
7485 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,
7486 1, 1, 1,
7487 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,
7488 2, 2, 2, 2, 2, 2,
7489 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,
7490 3, 3, 3, 3, 3,
7491 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,
7492 4, 4, 4, 4, 4, 4,
7493 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,
7494 5, 5, 5, 5, 5,
7495 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,
7496 6, 6, 6, 6, 6, 6,
7497 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,
7498 7, 7, 7, 7, 7, 7,
7499 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,
7500 8, 8, 8, 8, 8,
7501 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,
7502 9, 9, 9, 9, 9, 9,
7503 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7504 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7505 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7506 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7507
7508
7509// This function works for dates from 1970 to 2099.
7510static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007511 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007512#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007513 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007514#endif
7515
7516 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7517 date %= kDaysIn4Years;
7518
7519 month = kMonthInYear[date];
7520 day = kDayInYear[date];
7521
7522 ASSERT(MakeDay(year, month, day) == save_date);
7523}
7524
7525
7526static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007527 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007528#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007529 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007530#endif
7531
7532 date += kDaysOffset;
7533 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7534 date %= kDaysIn400Years;
7535
7536 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7537
7538 date--;
7539 int yd1 = date / kDaysIn100Years;
7540 date %= kDaysIn100Years;
7541 year += 100 * yd1;
7542
7543 date++;
7544 int yd2 = date / kDaysIn4Years;
7545 date %= kDaysIn4Years;
7546 year += 4 * yd2;
7547
7548 date--;
7549 int yd3 = date / 365;
7550 date %= 365;
7551 year += yd3;
7552
7553 bool is_leap = (!yd1 || yd2) && !yd3;
7554
7555 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007556 ASSERT(is_leap || (date >= 0));
7557 ASSERT((date < 365) || (is_leap && (date < 366)));
7558 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7559 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7560 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007561
7562 if (is_leap) {
7563 day = kDayInYear[2*365 + 1 + date];
7564 month = kMonthInYear[2*365 + 1 + date];
7565 } else {
7566 day = kDayInYear[date];
7567 month = kMonthInYear[date];
7568 }
7569
7570 ASSERT(MakeDay(year, month, day) == save_date);
7571}
7572
7573
7574static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007575 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007576 if (date >= 0 && date < 32 * kDaysIn4Years) {
7577 DateYMDFromTimeAfter1970(date, year, month, day);
7578 } else {
7579 DateYMDFromTimeSlow(date, year, month, day);
7580 }
7581}
7582
7583
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007584RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007585 NoHandleAllocation ha;
7586 ASSERT(args.length() == 2);
7587
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007588 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007589 CONVERT_CHECKED(JSArray, res_array, args[1]);
7590
7591 int year, month, day;
7592 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7593
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007594 RUNTIME_ASSERT(res_array->elements()->map() ==
7595 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007596 FixedArray* elms = FixedArray::cast(res_array->elements());
7597 RUNTIME_ASSERT(elms->length() == 3);
7598
7599 elms->set(0, Smi::FromInt(year));
7600 elms->set(1, Smi::FromInt(month));
7601 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007602
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007603 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007604}
7605
7606
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007607RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007608 HandleScope scope(isolate);
7609 ASSERT(args.length() == 3);
7610
7611 Handle<JSFunction> callee = args.at<JSFunction>(0);
7612 Object** parameters = reinterpret_cast<Object**>(args[1]);
7613 const int argument_count = Smi::cast(args[2])->value();
7614
7615 Handle<JSObject> result =
7616 isolate->factory()->NewArgumentsObject(callee, argument_count);
7617 // Allocate the elements if needed.
7618 int parameter_count = callee->shared()->formal_parameter_count();
7619 if (argument_count > 0) {
7620 if (parameter_count > 0) {
7621 int mapped_count = Min(argument_count, parameter_count);
7622 Handle<FixedArray> parameter_map =
7623 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7624 parameter_map->set_map(
7625 isolate->heap()->non_strict_arguments_elements_map());
7626
7627 Handle<Map> old_map(result->map());
7628 Handle<Map> new_map =
7629 isolate->factory()->CopyMapDropTransitions(old_map);
7630 new_map->set_elements_kind(JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
7631
7632 result->set_map(*new_map);
7633 result->set_elements(*parameter_map);
7634
7635 // Store the context and the arguments array at the beginning of the
7636 // parameter map.
7637 Handle<Context> context(isolate->context());
7638 Handle<FixedArray> arguments =
7639 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7640 parameter_map->set(0, *context);
7641 parameter_map->set(1, *arguments);
7642
7643 // Loop over the actual parameters backwards.
7644 int index = argument_count - 1;
7645 while (index >= mapped_count) {
7646 // These go directly in the arguments array and have no
7647 // corresponding slot in the parameter map.
7648 arguments->set(index, *(parameters - index - 1));
7649 --index;
7650 }
7651
7652 ScopeInfo<> scope_info(callee->shared()->scope_info());
7653 while (index >= 0) {
7654 // Detect duplicate names to the right in the parameter list.
7655 Handle<String> name = scope_info.parameter_name(index);
7656 int context_slot_count = scope_info.number_of_context_slots();
7657 bool duplicate = false;
7658 for (int j = index + 1; j < parameter_count; ++j) {
7659 if (scope_info.parameter_name(j).is_identical_to(name)) {
7660 duplicate = true;
7661 break;
7662 }
7663 }
7664
7665 if (duplicate) {
7666 // This goes directly in the arguments array with a hole in the
7667 // parameter map.
7668 arguments->set(index, *(parameters - index - 1));
7669 parameter_map->set_the_hole(index + 2);
7670 } else {
7671 // The context index goes in the parameter map with a hole in the
7672 // arguments array.
7673 int context_index = -1;
7674 for (int j = Context::MIN_CONTEXT_SLOTS;
7675 j < context_slot_count;
7676 ++j) {
7677 if (scope_info.context_slot_name(j).is_identical_to(name)) {
7678 context_index = j;
7679 break;
7680 }
7681 }
7682 ASSERT(context_index >= 0);
7683 arguments->set_the_hole(index);
7684 parameter_map->set(index + 2, Smi::FromInt(context_index));
7685 }
7686
7687 --index;
7688 }
7689 } else {
7690 // If there is no aliasing, the arguments object elements are not
7691 // special in any way.
7692 Handle<FixedArray> elements =
7693 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7694 result->set_elements(*elements);
7695 for (int i = 0; i < argument_count; ++i) {
7696 elements->set(i, *(parameters - i - 1));
7697 }
7698 }
7699 }
7700 return *result;
7701}
7702
7703
7704RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007705 NoHandleAllocation ha;
7706 ASSERT(args.length() == 3);
7707
7708 JSFunction* callee = JSFunction::cast(args[0]);
7709 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007710 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007711
lrn@chromium.org303ada72010-10-27 09:33:13 +00007712 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007713 { MaybeObject* maybe_result =
7714 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007715 if (!maybe_result->ToObject(&result)) return maybe_result;
7716 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007717 // Allocate the elements if needed.
7718 if (length > 0) {
7719 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007720 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007721 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007722 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7723 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007724
7725 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007726 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007727 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007728 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007729
7730 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007731 for (int i = 0; i < length; i++) {
7732 array->set(i, *--parameters, mode);
7733 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007734 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007735 }
7736 return result;
7737}
7738
7739
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007740RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007741 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007742 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007743 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007744 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007745 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007746
whesse@chromium.org7b260152011-06-20 15:33:18 +00007747 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007748 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007749 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007750 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007751 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7752 context,
7753 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007754 return *result;
7755}
7756
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007757
7758static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7759 int* total_argc) {
7760 // Find frame containing arguments passed to the caller.
7761 JavaScriptFrameIterator it;
7762 JavaScriptFrame* frame = it.frame();
7763 List<JSFunction*> functions(2);
7764 frame->GetFunctions(&functions);
7765 if (functions.length() > 1) {
7766 int inlined_frame_index = functions.length() - 1;
7767 JSFunction* inlined_function = functions[inlined_frame_index];
7768 int args_count = inlined_function->shared()->formal_parameter_count();
7769 ScopedVector<SlotRef> args_slots(args_count);
7770 SlotRef::ComputeSlotMappingForArguments(frame,
7771 inlined_frame_index,
7772 &args_slots);
7773
7774 *total_argc = bound_argc + args_count;
7775 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7776 for (int i = 0; i < args_count; i++) {
7777 Handle<Object> val = args_slots[i].GetValue();
7778 param_data[bound_argc + i] = val.location();
7779 }
7780 return param_data;
7781 } else {
7782 it.AdvanceToArgumentsFrame();
7783 frame = it.frame();
7784 int args_count = frame->ComputeParametersCount();
7785
7786 *total_argc = bound_argc + args_count;
7787 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7788 for (int i = 0; i < args_count; i++) {
7789 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7790 param_data[bound_argc + i] = val.location();
7791 }
7792 return param_data;
7793 }
7794}
7795
7796
7797RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007798 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007799 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007800 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007801 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007802
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007803 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007804 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007805 int bound_argc = 0;
7806 if (!args[1]->IsNull()) {
7807 CONVERT_ARG_CHECKED(JSArray, params, 1);
7808 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007809 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007810 bound_argc = Smi::cast(params->length())->value();
7811 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007812
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007813 int total_argc = 0;
7814 SmartPointer<Object**> param_data =
7815 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007816 for (int i = 0; i < bound_argc; i++) {
7817 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007818 param_data[i] = val.location();
7819 }
7820
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007821 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007822 Handle<Object> result =
7823 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007824 if (exception) {
7825 return Failure::Exception();
7826 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007827
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007828 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007829 return *result;
7830}
7831
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007832
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007833static void TrySettingInlineConstructStub(Isolate* isolate,
7834 Handle<JSFunction> function) {
7835 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007836 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007837 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007838 }
7839 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007840 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007841 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007842 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007843 function->shared()->set_construct_stub(
7844 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007845 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007846 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007847}
7848
7849
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007850RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007851 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007852 ASSERT(args.length() == 1);
7853
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007854 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007855
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007856 // If the constructor isn't a proper function we throw a type error.
7857 if (!constructor->IsJSFunction()) {
7858 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7859 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007860 isolate->factory()->NewTypeError("not_constructor", arguments);
7861 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007862 }
7863
7864 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007865
7866 // If function should not have prototype, construction is not allowed. In this
7867 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007868 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007869 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7870 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007871 isolate->factory()->NewTypeError("not_constructor", arguments);
7872 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007873 }
7874
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007875#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007876 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007877 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007878 if (debug->StepInActive()) {
7879 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007880 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007881#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007882
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007883 if (function->has_initial_map()) {
7884 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007885 // The 'Function' function ignores the receiver object when
7886 // called using 'new' and creates a new JSFunction object that
7887 // is returned. The receiver object is only used for error
7888 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007889 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007890 // allocate JSFunctions since it does not properly initialize
7891 // the shared part of the function. Since the receiver is
7892 // ignored anyway, we use the global object as the receiver
7893 // instead of a new JSFunction object. This way, errors are
7894 // reported the same way whether or not 'Function' is called
7895 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007896 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007897 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007898 }
7899
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007900 // The function should be compiled for the optimization hints to be
7901 // available. We cannot use EnsureCompiled because that forces a
7902 // compilation through the shared function info which makes it
7903 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007904 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007905 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007906
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007907 if (!function->has_initial_map() &&
7908 shared->IsInobjectSlackTrackingInProgress()) {
7909 // The tracking is already in progress for another function. We can only
7910 // track one initial_map at a time, so we force the completion before the
7911 // function is called as a constructor for the first time.
7912 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007913 }
7914
7915 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007916 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7917 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007918 // Delay setting the stub if inobject slack tracking is in progress.
7919 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007920 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007921 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007922
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007923 isolate->counters()->constructed_objects()->Increment();
7924 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007925
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007926 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007927}
7928
7929
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007930RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007931 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007932 ASSERT(args.length() == 1);
7933
7934 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7935 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007936 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007937
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007938 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007939}
7940
7941
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007942RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007943 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007944 ASSERT(args.length() == 1);
7945
7946 Handle<JSFunction> function = args.at<JSFunction>(0);
7947#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007948 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007949 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007950 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007951 PrintF("]\n");
7952 }
7953#endif
7954
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007955 // Compile the target function. Here we compile using CompileLazyInLoop in
7956 // order to get the optimized version. This helps code like delta-blue
7957 // that calls performance-critical routines through constructors. A
7958 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7959 // direct call. Since the in-loop tracking takes place through CallICs
7960 // this means that things called through constructors are never known to
7961 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007962 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007963 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007964 return Failure::Exception();
7965 }
7966
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007967 // All done. Return the compiled code.
7968 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007969 return function->code();
7970}
7971
7972
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007973RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007974 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007975 ASSERT(args.length() == 1);
7976 Handle<JSFunction> function = args.at<JSFunction>(0);
7977 // If the function is not optimizable or debugger is active continue using the
7978 // code from the full compiler.
7979 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007980 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007981 if (FLAG_trace_opt) {
7982 PrintF("[failed to optimize ");
7983 function->PrintName();
7984 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7985 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007986 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007987 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007988 function->ReplaceCode(function->shared()->code());
7989 return function->code();
7990 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007991 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007992 return function->code();
7993 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007994 if (FLAG_trace_opt) {
7995 PrintF("[failed to optimize ");
7996 function->PrintName();
7997 PrintF(": optimized compilation failed]\n");
7998 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007999 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008000 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008001}
8002
8003
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008004RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008005 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008006 ASSERT(args.length() == 1);
8007 RUNTIME_ASSERT(args[0]->IsSmi());
8008 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008009 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008010 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8011 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008012 int frames = deoptimizer->output_count();
8013
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008014 deoptimizer->MaterializeHeapNumbers();
8015 delete deoptimizer;
8016
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008017 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008018 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008019 for (int i = 0; i < frames - 1; i++) it.Advance();
8020 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008021
8022 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008023 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008024 Handle<Object> arguments;
8025 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008026 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008027 if (arguments.is_null()) {
8028 // FunctionGetArguments can't throw an exception, so cast away the
8029 // doubt with an assert.
8030 arguments = Handle<Object>(
8031 Accessors::FunctionGetArguments(*function,
8032 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008033 ASSERT(*arguments != isolate->heap()->null_value());
8034 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008035 }
8036 frame->SetExpression(i, *arguments);
8037 }
8038 }
8039
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008040 if (type == Deoptimizer::EAGER) {
8041 RUNTIME_ASSERT(function->IsOptimized());
8042 } else {
8043 RUNTIME_ASSERT(!function->IsOptimized());
8044 }
8045
8046 // Avoid doing too much work when running with --always-opt and keep
8047 // the optimized code around.
8048 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008049 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008050 }
8051
8052 // Count the number of optimized activations of the function.
8053 int activations = 0;
8054 while (!it.done()) {
8055 JavaScriptFrame* frame = it.frame();
8056 if (frame->is_optimized() && frame->function() == *function) {
8057 activations++;
8058 }
8059 it.Advance();
8060 }
8061
8062 // TODO(kasperl): For now, we cannot support removing the optimized
8063 // code when we have recursive invocations of the same function.
8064 if (activations == 0) {
8065 if (FLAG_trace_deopt) {
8066 PrintF("[removing optimized code for: ");
8067 function->PrintName();
8068 PrintF("]\n");
8069 }
8070 function->ReplaceCode(function->shared()->code());
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
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008076RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008077 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008078 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008079 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008080}
8081
8082
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008083RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008084 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008085 ASSERT(args.length() == 1);
8086 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008087 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008088
8089 Deoptimizer::DeoptimizeFunction(*function);
8090
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008091 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008092}
8093
8094
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008095RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8096#if defined(USE_SIMULATOR)
8097 return isolate->heap()->true_value();
8098#else
8099 return isolate->heap()->false_value();
8100#endif
8101}
8102
8103
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008104RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8105 HandleScope scope(isolate);
8106 ASSERT(args.length() == 1);
8107 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8108 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8109 function->MarkForLazyRecompilation();
8110 return isolate->heap()->undefined_value();
8111}
8112
8113
lrn@chromium.org1c092762011-05-09 09:42:16 +00008114RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8115 HandleScope scope(isolate);
8116 ASSERT(args.length() == 1);
8117 if (!V8::UseCrankshaft()) {
8118 return Smi::FromInt(4); // 4 == "never".
8119 }
8120 if (FLAG_always_opt) {
8121 return Smi::FromInt(3); // 3 == "always".
8122 }
8123 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8124 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8125 : Smi::FromInt(2); // 2 == "no".
8126}
8127
8128
8129RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8130 HandleScope scope(isolate);
8131 ASSERT(args.length() == 1);
8132 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8133 return Smi::FromInt(function->shared()->opt_count());
8134}
8135
8136
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008137RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008138 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008139 ASSERT(args.length() == 1);
8140 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8141
8142 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008143 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008144
8145 // We have hit a back edge in an unoptimized frame for a function that was
8146 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008147 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008148 // Keep track of whether we've succeeded in optimizing.
8149 bool succeeded = unoptimized->optimizable();
8150 if (succeeded) {
8151 // If we are trying to do OSR when there are already optimized
8152 // activations of the function, it means (a) the function is directly or
8153 // indirectly recursive and (b) an optimized invocation has been
8154 // deoptimized so that we are currently in an unoptimized activation.
8155 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008156 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008157 while (succeeded && !it.done()) {
8158 JavaScriptFrame* frame = it.frame();
8159 succeeded = !frame->is_optimized() || frame->function() != *function;
8160 it.Advance();
8161 }
8162 }
8163
8164 int ast_id = AstNode::kNoNumber;
8165 if (succeeded) {
8166 // The top JS function is this one, the PC is somewhere in the
8167 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008168 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008169 JavaScriptFrame* frame = it.frame();
8170 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008171 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008172 ASSERT(unoptimized->contains(frame->pc()));
8173
8174 // Use linear search of the unoptimized code's stack check table to find
8175 // the AST id matching the PC.
8176 Address start = unoptimized->instruction_start();
8177 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008178 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008179 uint32_t table_length = Memory::uint32_at(table_cursor);
8180 table_cursor += kIntSize;
8181 for (unsigned i = 0; i < table_length; ++i) {
8182 // Table entries are (AST id, pc offset) pairs.
8183 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8184 if (pc_offset == target_pc_offset) {
8185 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8186 break;
8187 }
8188 table_cursor += 2 * kIntSize;
8189 }
8190 ASSERT(ast_id != AstNode::kNoNumber);
8191 if (FLAG_trace_osr) {
8192 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8193 function->PrintName();
8194 PrintF("]\n");
8195 }
8196
8197 // Try to compile the optimized code. A true return value from
8198 // CompileOptimized means that compilation succeeded, not necessarily
8199 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008200 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
8201 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008202 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8203 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008204 if (data->OsrPcOffset()->value() >= 0) {
8205 if (FLAG_trace_osr) {
8206 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008207 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008208 }
8209 ASSERT(data->OsrAstId()->value() == ast_id);
8210 } else {
8211 // We may never generate the desired OSR entry if we emit an
8212 // early deoptimize.
8213 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008214 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008215 } else {
8216 succeeded = false;
8217 }
8218 }
8219
8220 // Revert to the original stack checks in the original unoptimized code.
8221 if (FLAG_trace_osr) {
8222 PrintF("[restoring original stack checks in ");
8223 function->PrintName();
8224 PrintF("]\n");
8225 }
8226 StackCheckStub check_stub;
8227 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008228 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008229 Deoptimizer::RevertStackCheckCode(*unoptimized,
8230 *check_code,
8231 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008232
8233 // Allow OSR only at nesting level zero again.
8234 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8235
8236 // If the optimization attempt succeeded, return the AST id tagged as a
8237 // smi. This tells the builtin that we need to translate the unoptimized
8238 // frame to an optimized one.
8239 if (succeeded) {
8240 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8241 return Smi::FromInt(ast_id);
8242 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008243 if (function->IsMarkedForLazyRecompilation()) {
8244 function->ReplaceCode(function->shared()->code());
8245 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008246 return Smi::FromInt(-1);
8247 }
8248}
8249
8250
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008251RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008252 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008253 ASSERT(args.length() == 1);
8254 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8255 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8256}
8257
8258
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008259RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008260 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008261 ASSERT(args.length() == 1);
8262 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8263 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8264}
8265
8266
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008267RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008268 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008269 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008270
kasper.lund7276f142008-07-30 08:49:36 +00008271 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00008272 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008273 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008274 { MaybeObject* maybe_result =
8275 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008276 if (!maybe_result->ToObject(&result)) return maybe_result;
8277 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008278
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008279 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008280
kasper.lund7276f142008-07-30 08:49:36 +00008281 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008282}
8283
lrn@chromium.org303ada72010-10-27 09:33:13 +00008284
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008285RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8286 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008287 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008288 JSObject* extension_object;
8289 if (args[0]->IsJSObject()) {
8290 extension_object = JSObject::cast(args[0]);
8291 } else {
8292 // Convert the object to a proper JavaScript object.
8293 MaybeObject* maybe_js_object = args[0]->ToObject();
8294 if (!maybe_js_object->To(&extension_object)) {
8295 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8296 HandleScope scope(isolate);
8297 Handle<Object> handle = args.at<Object>(0);
8298 Handle<Object> result =
8299 isolate->factory()->NewTypeError("with_expression",
8300 HandleVector(&handle, 1));
8301 return isolate->Throw(*result);
8302 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008303 return maybe_js_object;
8304 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008305 }
8306 }
8307
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008308 JSFunction* function;
8309 if (args[1]->IsSmi()) {
8310 // A smi sentinel indicates a context nested inside global code rather
8311 // than some function. There is a canonical empty function that can be
8312 // gotten from the global context.
8313 function = isolate->context()->global_context()->closure();
8314 } else {
8315 function = JSFunction::cast(args[1]);
8316 }
8317
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008318 Context* context;
8319 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008320 isolate->heap()->AllocateWithContext(function,
8321 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008322 extension_object);
8323 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008324 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008325 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008326}
8327
8328
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008329RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008330 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008331 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008332 String* name = String::cast(args[0]);
8333 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008334 JSFunction* function;
8335 if (args[2]->IsSmi()) {
8336 // A smi sentinel indicates a context nested inside global code rather
8337 // than some function. There is a canonical empty function that can be
8338 // gotten from the global context.
8339 function = isolate->context()->global_context()->closure();
8340 } else {
8341 function = JSFunction::cast(args[2]);
8342 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008343 Context* context;
8344 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008345 isolate->heap()->AllocateCatchContext(function,
8346 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008347 name,
8348 thrown_object);
8349 if (!maybe_context->To(&context)) return maybe_context;
8350 isolate->set_context(context);
8351 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008352}
8353
8354
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008355RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8356 NoHandleAllocation ha;
8357 ASSERT(args.length() == 2);
8358 SerializedScopeInfo* scope_info = SerializedScopeInfo::cast(args[0]);
8359 JSFunction* function;
8360 if (args[1]->IsSmi()) {
8361 // A smi sentinel indicates a context nested inside global code rather
8362 // than some function. There is a canonical empty function that can be
8363 // gotten from the global context.
8364 function = isolate->context()->global_context()->closure();
8365 } else {
8366 function = JSFunction::cast(args[1]);
8367 }
8368 Context* context;
8369 MaybeObject* maybe_context =
8370 isolate->heap()->AllocateBlockContext(function,
8371 isolate->context(),
8372 scope_info);
8373 if (!maybe_context->To(&context)) return maybe_context;
8374 isolate->set_context(context);
8375 return context;
8376}
8377
8378
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008379RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008380 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008381 ASSERT(args.length() == 2);
8382
8383 CONVERT_ARG_CHECKED(Context, context, 0);
8384 CONVERT_ARG_CHECKED(String, name, 1);
8385
8386 int index;
8387 PropertyAttributes attributes;
8388 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008389 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008390
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008391 // If the slot was not found the result is true.
8392 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008393 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008394 }
8395
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008396 // If the slot was found in a context, it should be DONT_DELETE.
8397 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008398 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008399 }
8400
8401 // The slot was found in a JSObject, either a context extension object,
8402 // the global object, or an arguments object. Try to delete it
8403 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
8404 // which allows deleting all parameters in functions that mention
8405 // 'arguments', we do this even for the case of slots found on an
8406 // arguments object. The slot was found on an arguments object if the
8407 // index is non-negative.
8408 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8409 if (index >= 0) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008410 return object->DeleteElement(index, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008411 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008412 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008413 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008414}
8415
8416
ager@chromium.orga1645e22009-09-09 19:27:10 +00008417// A mechanism to return a pair of Object pointers in registers (if possible).
8418// How this is achieved is calling convention-dependent.
8419// All currently supported x86 compiles uses calling conventions that are cdecl
8420// variants where a 64-bit value is returned in two 32-bit registers
8421// (edx:eax on ia32, r1:r0 on ARM).
8422// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8423// In Win64 calling convention, a struct of two pointers is returned in memory,
8424// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008425#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008426struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008427 MaybeObject* x;
8428 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008429};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008430
lrn@chromium.org303ada72010-10-27 09:33:13 +00008431static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008432 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008433 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8434 // In Win64 they are assigned to a hidden first argument.
8435 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008436}
8437#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008438typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008439static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008440 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008441 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008442}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008443#endif
8444
8445
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008446static inline MaybeObject* Unhole(Heap* heap,
8447 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008448 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008449 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8450 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008451 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008452}
8453
8454
danno@chromium.org40cb8782011-05-25 07:58:50 +00008455static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8456 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008457 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008458 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008459 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008460 JSFunction* context_extension_function =
8461 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008462 // If the holder isn't a context extension object, we just return it
8463 // as the receiver. This allows arguments objects to be used as
8464 // receivers, but only if they are put in the context scope chain
8465 // explicitly via a with-statement.
8466 Object* constructor = holder->map()->constructor();
8467 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008468 // Fall back to using the global object as the implicit receiver if
8469 // the property turns out to be a local variable allocated in a
8470 // context extension object - introduced via eval. Implicit global
8471 // receivers are indicated with the hole value.
8472 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008473}
8474
8475
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008476static ObjectPair LoadContextSlotHelper(Arguments args,
8477 Isolate* isolate,
8478 bool throw_error) {
8479 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008480 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008481
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008482 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008483 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008484 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008485 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008486 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008487
8488 int index;
8489 PropertyAttributes attributes;
8490 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008491 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008492
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008493 // If the index is non-negative, the slot has been found in a local
8494 // variable or a parameter. Read it from the context object or the
8495 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008496 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008497 // If the "property" we were looking for is a local variable or an
8498 // argument in a context, the receiver is the global object; see
8499 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008500 //
8501 // Use the hole as the receiver to signal that the receiver is
8502 // implicit and that the global receiver should be used.
8503 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008504 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008505 ? Context::cast(*holder)->get(index)
8506 : JSObject::cast(*holder)->GetElement(index);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008507 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008508 }
8509
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008510 // If the holder is found, we read the property from it.
8511 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008512 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008513 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008514 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008515 if (object->IsGlobalObject()) {
8516 receiver = GlobalObject::cast(object)->global_receiver();
8517 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008518 // Use the hole as the receiver to signal that the receiver is
8519 // implicit and that the global receiver should be used.
8520 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008521 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008522 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008523 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008524
8525 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008526 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008527
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008528 // No need to unhole the value here. This is taken care of by the
8529 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008530 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008531 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008532 }
8533
8534 if (throw_error) {
8535 // The property doesn't exist - throw exception.
8536 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008537 isolate->factory()->NewReferenceError("not_defined",
8538 HandleVector(&name, 1));
8539 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008540 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008541 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008542 return MakePair(isolate->heap()->undefined_value(),
8543 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008544 }
8545}
8546
8547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008548RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008549 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008550}
8551
8552
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008553RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008554 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008555}
8556
8557
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008558RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008559 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008560 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008561
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008562 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008563 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008564 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008565 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008566 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8567 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008568 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008569
8570 int index;
8571 PropertyAttributes attributes;
8572 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008573 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008574
8575 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008576 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008577 // Ignore if read_only variable.
8578 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008579 // Context is a fixed array and set cannot fail.
8580 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008581 } else if (strict_mode == kStrictMode) {
8582 // Setting read only property in strict mode.
8583 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008584 isolate->factory()->NewTypeError("strict_cannot_assign",
8585 HandleVector(&name, 1));
8586 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008587 }
8588 } else {
8589 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008590 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008591 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008592 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008593 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008594 return Failure::Exception();
8595 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008596 }
8597 return *value;
8598 }
8599
8600 // Slow case: The property is not in a FixedArray context.
8601 // It is either in an JSObject extension context or it was not found.
8602 Handle<JSObject> context_ext;
8603
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008604 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008605 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008606 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008607 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008608 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008609 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008610
8611 if (strict_mode == kStrictMode) {
8612 // Throw in strict mode (assignment to undefined variable).
8613 Handle<Object> error =
8614 isolate->factory()->NewReferenceError(
8615 "not_defined", HandleVector(&name, 1));
8616 return isolate->Throw(*error);
8617 }
8618 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008619 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008620 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008621 }
8622
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008623 // Set the property, but ignore if read_only variable on the context
8624 // extension object itself.
8625 if ((attributes & READ_ONLY) == 0 ||
8626 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008627 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008628 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008629 SetProperty(context_ext, name, value, NONE, strict_mode));
8630 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008631 // Setting read only property in strict mode.
8632 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008633 isolate->factory()->NewTypeError(
8634 "strict_cannot_assign", HandleVector(&name, 1));
8635 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008636 }
8637 return *value;
8638}
8639
8640
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008641RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008642 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008643 ASSERT(args.length() == 1);
8644
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008645 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008646}
8647
8648
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008649RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008650 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008651 ASSERT(args.length() == 1);
8652
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008653 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008654}
8655
8656
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008657RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008658 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008659 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008660}
8661
8662
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008663RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008664 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008665 ASSERT(args.length() == 1);
8666
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008667 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008668 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008669 isolate->factory()->NewReferenceError("not_defined",
8670 HandleVector(&name, 1));
8671 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008672}
8673
8674
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008675RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008676 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008677
8678 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008679 if (isolate->stack_guard()->IsStackOverflow()) {
8680 NoHandleAllocation na;
8681 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008682 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008683
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008684 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008685}
8686
8687
8688// NOTE: These PrintXXX functions are defined for all builds (not just
8689// DEBUG builds) because we may want to be able to trace function
8690// calls in all modes.
8691static void PrintString(String* str) {
8692 // not uncommon to have empty strings
8693 if (str->length() > 0) {
8694 SmartPointer<char> s =
8695 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8696 PrintF("%s", *s);
8697 }
8698}
8699
8700
8701static void PrintObject(Object* obj) {
8702 if (obj->IsSmi()) {
8703 PrintF("%d", Smi::cast(obj)->value());
8704 } else if (obj->IsString() || obj->IsSymbol()) {
8705 PrintString(String::cast(obj));
8706 } else if (obj->IsNumber()) {
8707 PrintF("%g", obj->Number());
8708 } else if (obj->IsFailure()) {
8709 PrintF("<failure>");
8710 } else if (obj->IsUndefined()) {
8711 PrintF("<undefined>");
8712 } else if (obj->IsNull()) {
8713 PrintF("<null>");
8714 } else if (obj->IsTrue()) {
8715 PrintF("<true>");
8716 } else if (obj->IsFalse()) {
8717 PrintF("<false>");
8718 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008719 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008720 }
8721}
8722
8723
8724static int StackSize() {
8725 int n = 0;
8726 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8727 return n;
8728}
8729
8730
8731static void PrintTransition(Object* result) {
8732 // indentation
8733 { const int nmax = 80;
8734 int n = StackSize();
8735 if (n <= nmax)
8736 PrintF("%4d:%*s", n, n, "");
8737 else
8738 PrintF("%4d:%*s", n, nmax, "...");
8739 }
8740
8741 if (result == NULL) {
8742 // constructor calls
8743 JavaScriptFrameIterator it;
8744 JavaScriptFrame* frame = it.frame();
8745 if (frame->IsConstructor()) PrintF("new ");
8746 // function name
8747 Object* fun = frame->function();
8748 if (fun->IsJSFunction()) {
8749 PrintObject(JSFunction::cast(fun)->shared()->name());
8750 } else {
8751 PrintObject(fun);
8752 }
8753 // function arguments
8754 // (we are intentionally only printing the actually
8755 // supplied parameters, not all parameters required)
8756 PrintF("(this=");
8757 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008758 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008759 for (int i = 0; i < length; i++) {
8760 PrintF(", ");
8761 PrintObject(frame->GetParameter(i));
8762 }
8763 PrintF(") {\n");
8764
8765 } else {
8766 // function result
8767 PrintF("} -> ");
8768 PrintObject(result);
8769 PrintF("\n");
8770 }
8771}
8772
8773
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008774RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008775 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008776 NoHandleAllocation ha;
8777 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008778 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008779}
8780
8781
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008782RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008783 NoHandleAllocation ha;
8784 PrintTransition(args[0]);
8785 return args[0]; // return TOS
8786}
8787
8788
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008789RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008790 NoHandleAllocation ha;
8791 ASSERT(args.length() == 1);
8792
8793#ifdef DEBUG
8794 if (args[0]->IsString()) {
8795 // If we have a string, assume it's a code "marker"
8796 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008797 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008798 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008799 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8800 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008801 } else {
8802 PrintF("DebugPrint: ");
8803 }
8804 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008805 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008806 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008807 HeapObject::cast(args[0])->map()->Print();
8808 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008809#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008810 // ShortPrint is available in release mode. Print is not.
8811 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008812#endif
8813 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008814 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008815
8816 return args[0]; // return TOS
8817}
8818
8819
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008820RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008821 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008822 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008823 isolate->PrintStack();
8824 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008825}
8826
8827
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008828RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008829 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008830 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008831
8832 // According to ECMA-262, section 15.9.1, page 117, the precision of
8833 // the number in a Date object representing a particular instant in
8834 // time is milliseconds. Therefore, we floor the result of getting
8835 // the OS time.
8836 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008837 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008838}
8839
8840
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008841RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008842 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008843 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008844
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008845 CONVERT_ARG_CHECKED(String, str, 0);
8846 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008847
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008848 CONVERT_ARG_CHECKED(JSArray, output, 1);
8849 RUNTIME_ASSERT(output->HasFastElements());
8850
8851 AssertNoAllocation no_allocation;
8852
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008853 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008854 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8855 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008856 String::FlatContent str_content = str->GetFlatContent();
8857 if (str_content.IsAscii()) {
8858 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008859 output_array,
8860 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008861 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008862 ASSERT(str_content.IsTwoByte());
8863 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008864 output_array,
8865 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008866 }
8867
8868 if (result) {
8869 return *output;
8870 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008871 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008872 }
8873}
8874
8875
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008876RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008877 NoHandleAllocation ha;
8878 ASSERT(args.length() == 1);
8879
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008880 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008881 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008882 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008883}
8884
8885
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008886RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008887 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008888 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008889
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008890 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008891}
8892
8893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008894RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008895 NoHandleAllocation ha;
8896 ASSERT(args.length() == 1);
8897
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008898 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008899 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008900}
8901
8902
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008903RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008904 ASSERT(args.length() == 1);
8905 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008906 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008907 return JSGlobalObject::cast(global)->global_receiver();
8908}
8909
8910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008911RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008912 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008913 ASSERT_EQ(1, args.length());
8914 CONVERT_ARG_CHECKED(String, source, 0);
8915
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008916 source = Handle<String>(source->TryFlattenGetString());
8917 // Optimized fast case where we only have ascii characters.
8918 Handle<Object> result;
8919 if (source->IsSeqAsciiString()) {
8920 result = JsonParser<true>::Parse(source);
8921 } else {
8922 result = JsonParser<false>::Parse(source);
8923 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008924 if (result.is_null()) {
8925 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008926 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008927 return Failure::Exception();
8928 }
8929 return *result;
8930}
8931
8932
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008933bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8934 Handle<Context> context) {
8935 if (context->allow_code_gen_from_strings()->IsFalse()) {
8936 // Check with callback if set.
8937 AllowCodeGenerationFromStringsCallback callback =
8938 isolate->allow_code_gen_callback();
8939 if (callback == NULL) {
8940 // No callback set and code generation disallowed.
8941 return false;
8942 } else {
8943 // Callback set. Let it decide if code generation is allowed.
8944 VMState state(isolate, EXTERNAL);
8945 return callback(v8::Utils::ToLocal(context));
8946 }
8947 }
8948 return true;
8949}
8950
8951
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008952RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008953 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008954 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008955 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008956
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008957 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008958 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008959
8960 // Check if global context allows code generation from
8961 // strings. Throw an exception if it doesn't.
8962 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8963 return isolate->Throw(*isolate->factory()->NewError(
8964 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8965 }
8966
8967 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008968 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8969 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008970 true,
8971 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008972 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008973 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008974 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8975 context,
8976 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008977 return *fun;
8978}
8979
8980
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008981static ObjectPair CompileGlobalEval(Isolate* isolate,
8982 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008983 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008984 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008985 Handle<Context> context = Handle<Context>(isolate->context());
8986 Handle<Context> global_context = Handle<Context>(context->global_context());
8987
8988 // Check if global context allows code generation from
8989 // strings. Throw an exception if it doesn't.
8990 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8991 isolate->Throw(*isolate->factory()->NewError(
8992 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8993 return MakePair(Failure::Exception(), NULL);
8994 }
8995
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008996 // Deal with a normal eval call with a string argument. Compile it
8997 // and return the compiled function bound in the local context.
8998 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8999 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009000 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009001 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009002 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009003 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009004 Handle<JSFunction> compiled =
9005 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009006 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009007 return MakePair(*compiled, *receiver);
9008}
9009
9010
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009011RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009012 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009013
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009014 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009015 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009016 Handle<Object> receiver; // Will be overwritten.
9017
9018 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009019 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009020#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009021 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009022 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009023 StackFrameLocator locator;
9024 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009025 ASSERT(Context::cast(frame->context()) == *context);
9026#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009027
9028 // Find where the 'eval' symbol is bound. It is unaliased only if
9029 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009030 int index = -1;
9031 PropertyAttributes attributes = ABSENT;
9032 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009033 receiver = context->Lookup(isolate->factory()->eval_symbol(),
9034 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009035 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009036 // Stop search when eval is found or when the global context is
9037 // reached.
9038 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009039 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009040 }
9041
iposva@chromium.org245aa852009-02-10 00:49:54 +00009042 // If eval could not be resolved, it has been deleted and we need to
9043 // throw a reference error.
9044 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009045 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00009046 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009047 isolate->factory()->NewReferenceError("not_defined",
9048 HandleVector(&name, 1));
9049 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009050 }
9051
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009052 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009053 // 'eval' is not bound in the global context. Just call the function
9054 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00009055 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009056 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009057 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009058 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009059 }
9060
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009061 // 'eval' is bound in the global context, but it may have been overwritten.
9062 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009063 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009064 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009065 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009066 }
9067
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009068 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009069 return CompileGlobalEval(isolate,
9070 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009071 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009072 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009073}
9074
9075
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009076RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009077 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009078
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009079 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009080 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009081
9082 // 'eval' is bound in the global context, but it may have been overwritten.
9083 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009084 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009085 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009086 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009087 }
9088
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009089 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009090 return CompileGlobalEval(isolate,
9091 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009092 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009093 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009094}
9095
9096
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009097RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009098 // This utility adjusts the property attributes for newly created Function
9099 // object ("new Function(...)") by changing the map.
9100 // All it does is changing the prototype property to enumerable
9101 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009102 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009103 ASSERT(args.length() == 1);
9104 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009105
9106 Handle<Map> map = func->shared()->strict_mode()
9107 ? isolate->strict_mode_function_instance_map()
9108 : isolate->function_instance_map();
9109
9110 ASSERT(func->map()->instance_type() == map->instance_type());
9111 ASSERT(func->map()->instance_size() == map->instance_size());
9112 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009113 return *func;
9114}
9115
9116
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009117RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009118 // Allocate a block of memory in NewSpace (filled with a filler).
9119 // Use as fallback for allocation in generated code when NewSpace
9120 // is full.
9121 ASSERT(args.length() == 1);
9122 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9123 int size = size_smi->value();
9124 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9125 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009126 Heap* heap = isolate->heap();
9127 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009128 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009129 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009130 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009131 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009132 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009133 }
9134 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009135 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009136}
9137
9138
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009139// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009140// array. Returns true if the element was pushed on the stack and
9141// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009142RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009143 ASSERT(args.length() == 2);
9144 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009145 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009146 RUNTIME_ASSERT(array->HasFastElements());
9147 int length = Smi::cast(array->length())->value();
9148 FixedArray* elements = FixedArray::cast(array->elements());
9149 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009150 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009151 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009152 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009153 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009154 { MaybeObject* maybe_obj =
9155 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009156 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9157 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009158 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009159}
9160
9161
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009162/**
9163 * A simple visitor visits every element of Array's.
9164 * The backend storage can be a fixed array for fast elements case,
9165 * or a dictionary for sparse array. Since Dictionary is a subtype
9166 * of FixedArray, the class can be used by both fast and slow cases.
9167 * The second parameter of the constructor, fast_elements, specifies
9168 * whether the storage is a FixedArray or Dictionary.
9169 *
9170 * An index limit is used to deal with the situation that a result array
9171 * length overflows 32-bit non-negative integer.
9172 */
9173class ArrayConcatVisitor {
9174 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009175 ArrayConcatVisitor(Isolate* isolate,
9176 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009177 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009178 isolate_(isolate),
9179 storage_(Handle<FixedArray>::cast(
9180 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009181 index_offset_(0u),
9182 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009183
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009184 ~ArrayConcatVisitor() {
9185 clear_storage();
9186 }
9187
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009188 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009189 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009190 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009191
9192 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009193 if (index < static_cast<uint32_t>(storage_->length())) {
9194 storage_->set(index, *elm);
9195 return;
9196 }
9197 // Our initial estimate of length was foiled, possibly by
9198 // getters on the arrays increasing the length of later arrays
9199 // during iteration.
9200 // This shouldn't happen in anything but pathological cases.
9201 SetDictionaryMode(index);
9202 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009203 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009204 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009205 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009206 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009207 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009208 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009209 // Dictionary needed to grow.
9210 clear_storage();
9211 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009212 }
9213}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009214
9215 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009216 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9217 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009218 } else {
9219 index_offset_ += delta;
9220 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009221 }
9222
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009223 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009224 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009225 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009226 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009227 Handle<Map> map;
9228 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009229 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009230 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009231 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009232 }
9233 array->set_map(*map);
9234 array->set_length(*length);
9235 array->set_elements(*storage_);
9236 return array;
9237 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009238
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009239 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009240 // Convert storage to dictionary mode.
9241 void SetDictionaryMode(uint32_t index) {
9242 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009243 Handle<FixedArray> current_storage(*storage_);
9244 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009245 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009246 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9247 for (uint32_t i = 0; i < current_length; i++) {
9248 HandleScope loop_scope;
9249 Handle<Object> element(current_storage->get(i));
9250 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009251 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009252 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009253 if (!new_storage.is_identical_to(slow_storage)) {
9254 slow_storage = loop_scope.CloseAndEscape(new_storage);
9255 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009256 }
9257 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009258 clear_storage();
9259 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009260 fast_elements_ = false;
9261 }
9262
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009263 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009264 isolate_->global_handles()->Destroy(
9265 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009266 }
9267
9268 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009269 storage_ = Handle<FixedArray>::cast(
9270 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009271 }
9272
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009273 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009274 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009275 // Index after last seen index. Always less than or equal to
9276 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009277 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009278 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009279};
9280
9281
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009282static uint32_t EstimateElementCount(Handle<JSArray> array) {
9283 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9284 int element_count = 0;
9285 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009286 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009287 // Fast elements can't have lengths that are not representable by
9288 // a 32-bit signed integer.
9289 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9290 int fast_length = static_cast<int>(length);
9291 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9292 for (int i = 0; i < fast_length; i++) {
9293 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009294 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009295 break;
9296 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009297 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009298 Handle<NumberDictionary> dictionary(
9299 NumberDictionary::cast(array->elements()));
9300 int capacity = dictionary->Capacity();
9301 for (int i = 0; i < capacity; i++) {
9302 Handle<Object> key(dictionary->KeyAt(i));
9303 if (dictionary->IsKey(*key)) {
9304 element_count++;
9305 }
9306 }
9307 break;
9308 }
9309 default:
9310 // External arrays are always dense.
9311 return length;
9312 }
9313 // As an estimate, we assume that the prototype doesn't contain any
9314 // inherited elements.
9315 return element_count;
9316}
9317
9318
9319
9320template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009321static void IterateExternalArrayElements(Isolate* isolate,
9322 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009323 bool elements_are_ints,
9324 bool elements_are_guaranteed_smis,
9325 ArrayConcatVisitor* visitor) {
9326 Handle<ExternalArrayClass> array(
9327 ExternalArrayClass::cast(receiver->elements()));
9328 uint32_t len = static_cast<uint32_t>(array->length());
9329
9330 ASSERT(visitor != NULL);
9331 if (elements_are_ints) {
9332 if (elements_are_guaranteed_smis) {
9333 for (uint32_t j = 0; j < len; j++) {
9334 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009335 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009336 visitor->visit(j, e);
9337 }
9338 } else {
9339 for (uint32_t j = 0; j < len; j++) {
9340 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009341 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009342 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9343 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9344 visitor->visit(j, e);
9345 } else {
9346 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009347 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009348 visitor->visit(j, e);
9349 }
9350 }
9351 }
9352 } else {
9353 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009354 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009355 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009356 visitor->visit(j, e);
9357 }
9358 }
9359}
9360
9361
9362// Used for sorting indices in a List<uint32_t>.
9363static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9364 uint32_t a = *ap;
9365 uint32_t b = *bp;
9366 return (a == b) ? 0 : (a < b) ? -1 : 1;
9367}
9368
9369
9370static void CollectElementIndices(Handle<JSObject> object,
9371 uint32_t range,
9372 List<uint32_t>* indices) {
9373 JSObject::ElementsKind kind = object->GetElementsKind();
9374 switch (kind) {
9375 case JSObject::FAST_ELEMENTS: {
9376 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9377 uint32_t length = static_cast<uint32_t>(elements->length());
9378 if (range < length) length = range;
9379 for (uint32_t i = 0; i < length; i++) {
9380 if (!elements->get(i)->IsTheHole()) {
9381 indices->Add(i);
9382 }
9383 }
9384 break;
9385 }
9386 case JSObject::DICTIONARY_ELEMENTS: {
9387 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009388 uint32_t capacity = dict->Capacity();
9389 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009390 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009391 Handle<Object> k(dict->KeyAt(j));
9392 if (dict->IsKey(*k)) {
9393 ASSERT(k->IsNumber());
9394 uint32_t index = static_cast<uint32_t>(k->Number());
9395 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009396 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009397 }
9398 }
9399 }
9400 break;
9401 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009402 default: {
9403 int dense_elements_length;
9404 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009405 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009406 dense_elements_length =
9407 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009408 break;
9409 }
9410 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009411 dense_elements_length =
9412 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009413 break;
9414 }
9415 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009416 dense_elements_length =
9417 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009418 break;
9419 }
9420 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009421 dense_elements_length =
9422 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009423 break;
9424 }
9425 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009426 dense_elements_length =
9427 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009428 break;
9429 }
9430 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009431 dense_elements_length =
9432 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009433 break;
9434 }
9435 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009436 dense_elements_length =
9437 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009438 break;
9439 }
9440 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009441 dense_elements_length =
9442 ExternalFloatArray::cast(object->elements())->length();
9443 break;
9444 }
9445 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9446 dense_elements_length =
9447 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009448 break;
9449 }
9450 default:
9451 UNREACHABLE();
9452 dense_elements_length = 0;
9453 break;
9454 }
9455 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9456 if (range <= length) {
9457 length = range;
9458 // We will add all indices, so we might as well clear it first
9459 // and avoid duplicates.
9460 indices->Clear();
9461 }
9462 for (uint32_t i = 0; i < length; i++) {
9463 indices->Add(i);
9464 }
9465 if (length == range) return; // All indices accounted for already.
9466 break;
9467 }
9468 }
9469
9470 Handle<Object> prototype(object->GetPrototype());
9471 if (prototype->IsJSObject()) {
9472 // The prototype will usually have no inherited element indices,
9473 // but we have to check.
9474 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9475 }
9476}
9477
9478
9479/**
9480 * A helper function that visits elements of a JSArray in numerical
9481 * order.
9482 *
9483 * The visitor argument called for each existing element in the array
9484 * with the element index and the element's value.
9485 * Afterwards it increments the base-index of the visitor by the array
9486 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009487 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009488 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009489static bool IterateElements(Isolate* isolate,
9490 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009491 ArrayConcatVisitor* visitor) {
9492 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9493 switch (receiver->GetElementsKind()) {
9494 case JSObject::FAST_ELEMENTS: {
9495 // Run through the elements FixedArray and use HasElement and GetElement
9496 // to check the prototype for missing elements.
9497 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9498 int fast_length = static_cast<int>(length);
9499 ASSERT(fast_length <= elements->length());
9500 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009501 HandleScope loop_scope(isolate);
9502 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009503 if (!element_value->IsTheHole()) {
9504 visitor->visit(j, element_value);
9505 } else if (receiver->HasElement(j)) {
9506 // Call GetElement on receiver, not its prototype, or getters won't
9507 // have the correct receiver.
9508 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009509 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009510 visitor->visit(j, element_value);
9511 }
9512 }
9513 break;
9514 }
9515 case JSObject::DICTIONARY_ELEMENTS: {
9516 Handle<NumberDictionary> dict(receiver->element_dictionary());
9517 List<uint32_t> indices(dict->Capacity() / 2);
9518 // Collect all indices in the object and the prototypes less
9519 // than length. This might introduce duplicates in the indices list.
9520 CollectElementIndices(receiver, length, &indices);
9521 indices.Sort(&compareUInt32);
9522 int j = 0;
9523 int n = indices.length();
9524 while (j < n) {
9525 HandleScope loop_scope;
9526 uint32_t index = indices[j];
9527 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009528 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009529 visitor->visit(index, element);
9530 // Skip to next different index (i.e., omit duplicates).
9531 do {
9532 j++;
9533 } while (j < n && indices[j] == index);
9534 }
9535 break;
9536 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009537 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
9538 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9539 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009540 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009541 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009542 visitor->visit(j, e);
9543 }
9544 break;
9545 }
9546 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
9547 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009548 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009549 break;
9550 }
9551 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9552 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009553 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009554 break;
9555 }
9556 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
9557 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009558 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009559 break;
9560 }
9561 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9562 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009563 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009564 break;
9565 }
9566 case JSObject::EXTERNAL_INT_ELEMENTS: {
9567 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009568 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009569 break;
9570 }
9571 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9572 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009573 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009574 break;
9575 }
9576 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9577 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009578 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009579 break;
9580 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009581 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9582 IterateExternalArrayElements<ExternalDoubleArray, double>(
9583 isolate, receiver, false, false, visitor);
9584 break;
9585 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009586 default:
9587 UNREACHABLE();
9588 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009589 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009590 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009591 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009592}
9593
9594
9595/**
9596 * Array::concat implementation.
9597 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009598 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009599 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009600 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009601RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009602 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009603 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009604
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009605 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9606 int argument_count = static_cast<int>(arguments->length()->Number());
9607 RUNTIME_ASSERT(arguments->HasFastElements());
9608 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009609
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009610 // Pass 1: estimate the length and number of elements of the result.
9611 // The actual length can be larger if any of the arguments have getters
9612 // that mutate other arguments (but will otherwise be precise).
9613 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009614
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009615 uint32_t estimate_result_length = 0;
9616 uint32_t estimate_nof_elements = 0;
9617 {
9618 for (int i = 0; i < argument_count; i++) {
9619 HandleScope loop_scope;
9620 Handle<Object> obj(elements->get(i));
9621 uint32_t length_estimate;
9622 uint32_t element_estimate;
9623 if (obj->IsJSArray()) {
9624 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9625 length_estimate =
9626 static_cast<uint32_t>(array->length()->Number());
9627 element_estimate =
9628 EstimateElementCount(array);
9629 } else {
9630 length_estimate = 1;
9631 element_estimate = 1;
9632 }
9633 // Avoid overflows by capping at kMaxElementCount.
9634 if (JSObject::kMaxElementCount - estimate_result_length <
9635 length_estimate) {
9636 estimate_result_length = JSObject::kMaxElementCount;
9637 } else {
9638 estimate_result_length += length_estimate;
9639 }
9640 if (JSObject::kMaxElementCount - estimate_nof_elements <
9641 element_estimate) {
9642 estimate_nof_elements = JSObject::kMaxElementCount;
9643 } else {
9644 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009645 }
9646 }
9647 }
9648
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009649 // If estimated number of elements is more than half of length, a
9650 // fixed array (fast case) is more time and space-efficient than a
9651 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009652 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009653
9654 Handle<FixedArray> storage;
9655 if (fast_case) {
9656 // The backing storage array must have non-existing elements to
9657 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009658 storage = isolate->factory()->NewFixedArrayWithHoles(
9659 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009660 } else {
9661 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9662 uint32_t at_least_space_for = estimate_nof_elements +
9663 (estimate_nof_elements >> 2);
9664 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009665 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009666 }
9667
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009668 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009669
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009670 for (int i = 0; i < argument_count; i++) {
9671 Handle<Object> obj(elements->get(i));
9672 if (obj->IsJSArray()) {
9673 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009674 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009675 return Failure::Exception();
9676 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009677 } else {
9678 visitor.visit(0, obj);
9679 visitor.increase_index_offset(1);
9680 }
9681 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009682
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009683 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009684}
9685
9686
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009687// This will not allocate (flatten the string), but it may run
9688// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009689RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009690 NoHandleAllocation ha;
9691 ASSERT(args.length() == 1);
9692
9693 CONVERT_CHECKED(String, string, args[0]);
9694 StringInputBuffer buffer(string);
9695 while (buffer.has_more()) {
9696 uint16_t character = buffer.GetNext();
9697 PrintF("%c", character);
9698 }
9699 return string;
9700}
9701
ager@chromium.org5ec48922009-05-05 07:25:34 +00009702// Moves all own elements of an object, that are below a limit, to positions
9703// starting at zero. All undefined values are placed after non-undefined values,
9704// and are followed by non-existing element. Does not change the length
9705// property.
9706// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009707RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009708 ASSERT(args.length() == 2);
9709 CONVERT_CHECKED(JSObject, object, args[0]);
9710 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9711 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009712}
9713
9714
9715// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009716RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009717 ASSERT(args.length() == 2);
9718 CONVERT_CHECKED(JSArray, from, args[0]);
9719 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009720 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009721 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009722 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9723 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009724 maybe_new_map = to->map()->GetFastElementsMap();
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009725 } else if (new_elements->map() ==
9726 isolate->heap()->fixed_double_array_map()) {
9727 maybe_new_map = to->map()->GetFastDoubleElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009728 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009729 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009730 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009731 Object* new_map;
9732 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009733 to->set_map(Map::cast(new_map));
9734 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009735 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009736 Object* obj;
9737 { MaybeObject* maybe_obj = from->ResetElements();
9738 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9739 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009740 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009741 return to;
9742}
9743
9744
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009745// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009746RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009747 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009748 CONVERT_CHECKED(JSObject, object, args[0]);
9749 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009750 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009751 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009752 } else if (object->IsJSArray()) {
9753 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009754 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009755 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009756 }
9757}
9758
9759
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009760RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009761 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009762
9763 ASSERT_EQ(3, args.length());
9764
ager@chromium.orgac091b72010-05-05 07:34:42 +00009765 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009766 Handle<Object> key1 = args.at<Object>(1);
9767 Handle<Object> key2 = args.at<Object>(2);
9768
9769 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009770 if (!key1->ToArrayIndex(&index1)
9771 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009772 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009773 }
9774
ager@chromium.orgac091b72010-05-05 07:34:42 +00009775 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9776 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009777 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009778 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009779 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009780
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009781 RETURN_IF_EMPTY_HANDLE(isolate,
9782 SetElement(jsobject, index1, tmp2, kStrictMode));
9783 RETURN_IF_EMPTY_HANDLE(isolate,
9784 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009785
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009786 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009787}
9788
9789
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009790// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009791// might have elements. Can either return keys (positive integers) or
9792// intervals (pair of a negative integer (-start-1) followed by a
9793// positive (length)) or undefined values.
9794// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009795RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009796 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009797 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009798 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009799 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009800 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009801 // Create an array and get all the keys into it, then remove all the
9802 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009803 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009804 int keys_length = keys->length();
9805 for (int i = 0; i < keys_length; i++) {
9806 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009807 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009808 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009809 // Zap invalid keys.
9810 keys->set_undefined(i);
9811 }
9812 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009813 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009814 } else {
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009815 ASSERT(array->HasFastElements() || array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009816 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009817 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009818 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009819 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009820 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009821 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009822 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009823 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009824 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009825 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009826 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009827 }
9828}
9829
9830
9831// DefineAccessor takes an optional final argument which is the
9832// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9833// to the way accessors are implemented, it is set for both the getter
9834// and setter on the first call to DefineAccessor and ignored on
9835// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009836RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009837 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9838 // Compute attributes.
9839 PropertyAttributes attributes = NONE;
9840 if (args.length() == 5) {
9841 CONVERT_CHECKED(Smi, attrs, args[4]);
9842 int value = attrs->value();
9843 // Only attribute bits should be set.
9844 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9845 attributes = static_cast<PropertyAttributes>(value);
9846 }
9847
9848 CONVERT_CHECKED(JSObject, obj, args[0]);
9849 CONVERT_CHECKED(String, name, args[1]);
9850 CONVERT_CHECKED(Smi, flag, args[2]);
9851 CONVERT_CHECKED(JSFunction, fun, args[3]);
9852 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9853}
9854
9855
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009856RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009857 ASSERT(args.length() == 3);
9858 CONVERT_CHECKED(JSObject, obj, args[0]);
9859 CONVERT_CHECKED(String, name, args[1]);
9860 CONVERT_CHECKED(Smi, flag, args[2]);
9861 return obj->LookupAccessor(name, flag->value() == 0);
9862}
9863
9864
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009865#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009866RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009867 ASSERT(args.length() == 0);
9868 return Execution::DebugBreakHelper();
9869}
9870
9871
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009872// Helper functions for wrapping and unwrapping stack frame ids.
9873static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009874 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009875 return Smi::FromInt(id >> 2);
9876}
9877
9878
9879static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9880 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9881}
9882
9883
9884// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009885// args[0]: debug event listener function to set or null or undefined for
9886// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009887// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009888RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009889 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009890 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9891 args[0]->IsUndefined() ||
9892 args[0]->IsNull());
9893 Handle<Object> callback = args.at<Object>(0);
9894 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009895 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009896
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009897 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009898}
9899
9900
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009901RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009902 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009903 isolate->stack_guard()->DebugBreak();
9904 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009905}
9906
9907
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009908static MaybeObject* DebugLookupResultValue(Heap* heap,
9909 Object* receiver,
9910 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009911 LookupResult* result,
9912 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009913 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009914 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009915 case NORMAL:
9916 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009917 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009918 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009919 }
9920 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009921 case FIELD:
9922 value =
9923 JSObject::cast(
9924 result->holder())->FastPropertyAt(result->GetFieldIndex());
9925 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009926 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009927 }
9928 return value;
9929 case CONSTANT_FUNCTION:
9930 return result->GetConstantFunction();
9931 case CALLBACKS: {
9932 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009933 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009934 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009935 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009936 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009937 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009938 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009939 maybe_value = heap->isolate()->pending_exception();
9940 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009941 if (caught_exception != NULL) {
9942 *caught_exception = true;
9943 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009944 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009945 }
9946 return value;
9947 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009948 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009949 }
9950 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009951 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009952 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009953 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009954 case CONSTANT_TRANSITION:
9955 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009956 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009957 default:
9958 UNREACHABLE();
9959 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009960 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009961 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009962}
9963
9964
ager@chromium.org32912102009-01-16 10:38:43 +00009965// Get debugger related details for an object property.
9966// args[0]: object holding property
9967// args[1]: name of the property
9968//
9969// The array returned contains the following information:
9970// 0: Property value
9971// 1: Property details
9972// 2: Property value is exception
9973// 3: Getter function if defined
9974// 4: Setter function if defined
9975// Items 2-4 are only filled if the property has either a getter or a setter
9976// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009977RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009978 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009979
9980 ASSERT(args.length() == 2);
9981
9982 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9983 CONVERT_ARG_CHECKED(String, name, 1);
9984
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009985 // Make sure to set the current context to the context before the debugger was
9986 // entered (if the debugger is entered). The reason for switching context here
9987 // is that for some property lookups (accessors and interceptors) callbacks
9988 // into the embedding application can occour, and the embedding application
9989 // could have the assumption that its own global context is the current
9990 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009991 SaveContext save(isolate);
9992 if (isolate->debug()->InDebugger()) {
9993 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009994 }
9995
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009996 // Skip the global proxy as it has no properties and always delegates to the
9997 // real global object.
9998 if (obj->IsJSGlobalProxy()) {
9999 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10000 }
10001
10002
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010003 // Check if the name is trivially convertible to an index and get the element
10004 // if so.
10005 uint32_t index;
10006 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010007 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010008 Object* element_or_char;
10009 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010010 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010011 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10012 return maybe_element_or_char;
10013 }
10014 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010015 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010016 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010017 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010018 }
10019
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010020 // Find the number of objects making up this.
10021 int length = LocalPrototypeChainLength(*obj);
10022
10023 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010024 Handle<JSObject> jsproto = obj;
10025 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010026 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010027 jsproto->LocalLookup(*name, &result);
10028 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010029 // LookupResult is not GC safe as it holds raw object pointers.
10030 // GC can happen later in this code so put the required fields into
10031 // local variables using handles when required for later use.
10032 PropertyType result_type = result.type();
10033 Handle<Object> result_callback_obj;
10034 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010035 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10036 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010037 }
10038 Smi* property_details = result.GetPropertyDetails().AsSmi();
10039 // DebugLookupResultValue can cause GC so details from LookupResult needs
10040 // to be copied to handles before this.
10041 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010042 Object* raw_value;
10043 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010044 DebugLookupResultValue(isolate->heap(), *obj, *name,
10045 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010046 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10047 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010048 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010049
10050 // If the callback object is a fixed array then it contains JavaScript
10051 // getter and/or setter.
10052 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
10053 result_callback_obj->IsFixedArray();
10054 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010055 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010056 details->set(0, *value);
10057 details->set(1, property_details);
10058 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010059 details->set(2, isolate->heap()->ToBoolean(caught_exception));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010060 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
10061 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
10062 }
10063
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010064 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010065 }
10066 if (i < length - 1) {
10067 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10068 }
10069 }
10070
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010071 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010072}
10073
10074
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010075RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010076 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010077
10078 ASSERT(args.length() == 2);
10079
10080 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10081 CONVERT_ARG_CHECKED(String, name, 1);
10082
10083 LookupResult result;
10084 obj->Lookup(*name, &result);
10085 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010086 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010087 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010088 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010089}
10090
10091
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010092// Return the property type calculated from the property details.
10093// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010094RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010095 ASSERT(args.length() == 1);
10096 CONVERT_CHECKED(Smi, details, args[0]);
10097 PropertyType type = PropertyDetails(details).type();
10098 return Smi::FromInt(static_cast<int>(type));
10099}
10100
10101
10102// Return the property attribute calculated from the property details.
10103// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010104RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010105 ASSERT(args.length() == 1);
10106 CONVERT_CHECKED(Smi, details, args[0]);
10107 PropertyAttributes attributes = PropertyDetails(details).attributes();
10108 return Smi::FromInt(static_cast<int>(attributes));
10109}
10110
10111
10112// Return the property insertion index calculated from the property details.
10113// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010114RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010115 ASSERT(args.length() == 1);
10116 CONVERT_CHECKED(Smi, details, args[0]);
10117 int index = PropertyDetails(details).index();
10118 return Smi::FromInt(index);
10119}
10120
10121
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010122// Return property value from named interceptor.
10123// args[0]: object
10124// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010125RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010126 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010127 ASSERT(args.length() == 2);
10128 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10129 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10130 CONVERT_ARG_CHECKED(String, name, 1);
10131
10132 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010133 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010134}
10135
10136
10137// Return element value from indexed interceptor.
10138// args[0]: object
10139// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010140RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010141 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010142 ASSERT(args.length() == 2);
10143 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10144 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10145 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10146
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010147 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010148}
10149
10150
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010151RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010152 ASSERT(args.length() >= 1);
10153 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010154 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010155 if (isolate->debug()->break_id() == 0 ||
10156 break_id != isolate->debug()->break_id()) {
10157 return isolate->Throw(
10158 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010159 }
10160
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010161 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010162}
10163
10164
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010165RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010166 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010167 ASSERT(args.length() == 1);
10168
10169 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010170 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010171 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10172 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010173 if (!maybe_result->ToObject(&result)) return maybe_result;
10174 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010175
10176 // Count all frames which are relevant to debugging stack trace.
10177 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010178 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010179 if (id == StackFrame::NO_ID) {
10180 // If there is no JavaScript stack frame count is 0.
10181 return Smi::FromInt(0);
10182 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010183
10184 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10185 n += it.frame()->GetInlineCount();
10186 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010187 return Smi::FromInt(n);
10188}
10189
10190
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010191class FrameInspector {
10192 public:
10193 FrameInspector(JavaScriptFrame* frame,
10194 int inlined_frame_index,
10195 Isolate* isolate)
10196 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10197 // Calculate the deoptimized frame.
10198 if (frame->is_optimized()) {
10199 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10200 frame, inlined_frame_index, isolate);
10201 }
10202 has_adapted_arguments_ = frame_->has_adapted_arguments();
10203 is_optimized_ = frame_->is_optimized();
10204 }
10205
10206 ~FrameInspector() {
10207 // Get rid of the calculated deoptimized frame if any.
10208 if (deoptimized_frame_ != NULL) {
10209 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10210 isolate_);
10211 }
10212 }
10213
10214 int GetParametersCount() {
10215 return is_optimized_
10216 ? deoptimized_frame_->parameters_count()
10217 : frame_->ComputeParametersCount();
10218 }
10219 int expression_count() { return deoptimized_frame_->expression_count(); }
10220 Object* GetFunction() {
10221 return is_optimized_
10222 ? deoptimized_frame_->GetFunction()
10223 : frame_->function();
10224 }
10225 Object* GetParameter(int index) {
10226 return is_optimized_
10227 ? deoptimized_frame_->GetParameter(index)
10228 : frame_->GetParameter(index);
10229 }
10230 Object* GetExpression(int index) {
10231 return is_optimized_
10232 ? deoptimized_frame_->GetExpression(index)
10233 : frame_->GetExpression(index);
10234 }
10235
10236 // To inspect all the provided arguments the frame might need to be
10237 // replaced with the arguments frame.
10238 void SetArgumentsFrame(JavaScriptFrame* frame) {
10239 ASSERT(has_adapted_arguments_);
10240 frame_ = frame;
10241 is_optimized_ = frame_->is_optimized();
10242 ASSERT(!is_optimized_);
10243 }
10244
10245 private:
10246 JavaScriptFrame* frame_;
10247 DeoptimizedFrameInfo* deoptimized_frame_;
10248 Isolate* isolate_;
10249 bool is_optimized_;
10250 bool has_adapted_arguments_;
10251
10252 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10253};
10254
10255
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010256static const int kFrameDetailsFrameIdIndex = 0;
10257static const int kFrameDetailsReceiverIndex = 1;
10258static const int kFrameDetailsFunctionIndex = 2;
10259static const int kFrameDetailsArgumentCountIndex = 3;
10260static const int kFrameDetailsLocalCountIndex = 4;
10261static const int kFrameDetailsSourcePositionIndex = 5;
10262static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010263static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010264static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010265static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010266
10267// Return an array with frame details
10268// args[0]: number: break id
10269// args[1]: number: frame index
10270//
10271// The array returned contains the following information:
10272// 0: Frame id
10273// 1: Receiver
10274// 2: Function
10275// 3: Argument count
10276// 4: Local count
10277// 5: Source position
10278// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010279// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010280// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010281// Arguments name, value
10282// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010283// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010284RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010285 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010286 ASSERT(args.length() == 2);
10287
10288 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010289 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010290 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10291 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010292 if (!maybe_check->ToObject(&check)) return maybe_check;
10293 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010294 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010295 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010296
10297 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010298 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010299 if (id == StackFrame::NO_ID) {
10300 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010301 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010302 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010303
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010304 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010305
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010306 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010307 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010308 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010309 if (index < count + it.frame()->GetInlineCount()) break;
10310 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010311 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010312 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010313
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010314 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010315 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010316 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010317 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010318 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010319
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010320 // Traverse the saved contexts chain to find the active context for the
10321 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010322 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010323 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010324 save = save->prev();
10325 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010326 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010327
10328 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010329 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010330
10331 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010332 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010333 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010334
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010335 // Check for constructor frame. Inlined frames cannot be construct calls.
10336 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010337 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010338 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010339
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010340 // Get scope info and read from it for local variable information.
10341 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010342 Handle<SharedFunctionInfo> shared(function->shared());
10343 Handle<SerializedScopeInfo> scope_info(shared->scope_info());
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010344 ASSERT(*scope_info != SerializedScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010345 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010346
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010347 // Get the locals names and values into a temporary array.
10348 //
10349 // TODO(1240907): Hide compiler-introduced stack variables
10350 // (e.g. .result)? For users of the debugger, they will probably be
10351 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010352 Handle<FixedArray> locals =
10353 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010354
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010355 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010356 int i = 0;
10357 for (; i < info.number_of_stack_slots(); ++i) {
10358 // Use the value from the stack.
10359 locals->set(i * 2, *info.LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010360 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010361 }
10362 if (i < info.NumberOfLocals()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010363 // Get the context containing declarations.
10364 Handle<Context> context(
10365 Context::cast(it.frame()->context())->declaration_context());
10366 for (; i < info.NumberOfLocals(); ++i) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010367 Handle<String> name = info.LocalName(i);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010368 locals->set(i * 2, *name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010369 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010370 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010371 }
10372 }
10373
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010374 // Check whether this frame is positioned at return. If not top
10375 // frame or if the frame is optimized it cannot be at a return.
10376 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010377 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010378 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010379 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010380
10381 // If positioned just before return find the value to be returned and add it
10382 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010383 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010384 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010385 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010386 Address internal_frame_sp = NULL;
10387 while (!it2.done()) {
10388 if (it2.frame()->is_internal()) {
10389 internal_frame_sp = it2.frame()->sp();
10390 } else {
10391 if (it2.frame()->is_java_script()) {
10392 if (it2.frame()->id() == it.frame()->id()) {
10393 // The internal frame just before the JavaScript frame contains the
10394 // value to return on top. A debug break at return will create an
10395 // internal frame to store the return value (eax/rax/r0) before
10396 // entering the debug break exit frame.
10397 if (internal_frame_sp != NULL) {
10398 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010399 Handle<Object>(Memory::Object_at(internal_frame_sp),
10400 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010401 break;
10402 }
10403 }
10404 }
10405
10406 // Indicate that the previous frame was not an internal frame.
10407 internal_frame_sp = NULL;
10408 }
10409 it2.Advance();
10410 }
10411 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010412
10413 // Now advance to the arguments adapter frame (if any). It contains all
10414 // the provided parameters whereas the function frame always have the number
10415 // of arguments matching the functions parameters. The rest of the
10416 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010417 if (it.frame()->has_adapted_arguments()) {
10418 it.AdvanceToArgumentsFrame();
10419 frame_inspector.SetArgumentsFrame(it.frame());
10420 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010421
10422 // Find the number of arguments to fill. At least fill the number of
10423 // parameters for the function and fill more if more parameters are provided.
10424 int argument_count = info.number_of_parameters();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010425 if (argument_count < frame_inspector.GetParametersCount()) {
10426 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010427 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010428#ifdef DEBUG
10429 if (it.frame()->is_optimized()) {
10430 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10431 }
10432#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010433
10434 // Calculate the size of the result.
10435 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010436 2 * (argument_count + info.NumberOfLocals()) +
10437 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010438 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010439
10440 // Add the frame id.
10441 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10442
10443 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010444 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010445
10446 // Add the arguments count.
10447 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10448
10449 // Add the locals count
10450 details->set(kFrameDetailsLocalCountIndex,
10451 Smi::FromInt(info.NumberOfLocals()));
10452
10453 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010454 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010455 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10456 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010457 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010458 }
10459
10460 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010461 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010462
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010463 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010464 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010465
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010466 // Add flags to indicate information on whether this frame is
10467 // bit 0: invoked in the debugger context.
10468 // bit 1: optimized frame.
10469 // bit 2: inlined in optimized frame
10470 int flags = 0;
10471 if (*save->context() == *isolate->debug()->debug_context()) {
10472 flags |= 1 << 0;
10473 }
10474 if (it.frame()->is_optimized()) {
10475 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010476 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010477 }
10478 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010479
10480 // Fill the dynamic part.
10481 int details_index = kFrameDetailsFirstDynamicIndex;
10482
10483 // Add arguments name and value.
10484 for (int i = 0; i < argument_count; i++) {
10485 // Name of the argument.
10486 if (i < info.number_of_parameters()) {
10487 details->set(details_index++, *info.parameter_name(i));
10488 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010489 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010490 }
10491
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010492 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010493 if (i < it.frame()->ComputeParametersCount()) {
10494 // Get the value from the stack.
10495 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010496 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010497 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010498 }
10499 }
10500
10501 // Add locals name and value from the temporary copy from the function frame.
10502 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10503 details->set(details_index++, locals->get(i));
10504 }
10505
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010506 // Add the value being returned.
10507 if (at_return) {
10508 details->set(details_index++, *return_value);
10509 }
10510
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010511 // Add the receiver (same as in function frame).
10512 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10513 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010514 Handle<Object> receiver(it.frame()->receiver(), isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010515 if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
10516 // If the receiver is not a JSObject and the function is not a
10517 // builtin or strict-mode we have hit an optimization where a
10518 // value object is not converted into a wrapped JS objects. To
10519 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010520 // by creating correct wrapper object based on the calling frame's
10521 // global context.
10522 it.Advance();
10523 Handle<Context> calling_frames_global_context(
10524 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010525 receiver =
10526 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010527 }
10528 details->set(kFrameDetailsReceiverIndex, *receiver);
10529
10530 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010531 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010532}
10533
10534
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010535// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010536static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010537 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010538 Handle<SerializedScopeInfo> serialized_scope_info,
10539 ScopeInfo<>& scope_info,
10540 Handle<Context> context,
10541 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010542 // Fill all context locals to the context extension.
10543 for (int i = Context::MIN_CONTEXT_SLOTS;
10544 i < scope_info.number_of_context_slots();
10545 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010546 int context_index = serialized_scope_info->ContextSlotIndex(
10547 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010548
whesse@chromium.org7b260152011-06-20 15:33:18 +000010549 RETURN_IF_EMPTY_HANDLE_VALUE(
10550 isolate,
10551 SetProperty(scope_object,
10552 scope_info.context_slot_name(i),
10553 Handle<Object>(context->get(context_index), isolate),
10554 NONE,
10555 kNonStrictMode),
10556 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010557 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010558
10559 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010560}
10561
10562
10563// Create a plain JSObject which materializes the local scope for the specified
10564// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010565static Handle<JSObject> MaterializeLocalScope(
10566 Isolate* isolate,
10567 JavaScriptFrame* frame,
10568 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010569 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010570 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010571 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10572 ScopeInfo<> scope_info(*serialized_scope_info);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010573 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010574
10575 // Allocate and initialize a JSObject with all the arguments, stack locals
10576 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010577 Handle<JSObject> local_scope =
10578 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010579
10580 // First fill all parameters.
10581 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010582 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010583 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010584 SetProperty(local_scope,
10585 scope_info.parameter_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010586 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010587 NONE,
10588 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010589 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010590 }
10591
10592 // Second fill all stack locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010593 for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010594 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010595 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010596 SetProperty(local_scope,
10597 scope_info.stack_slot_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010598 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010599 NONE,
10600 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010601 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010602 }
10603
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010604 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10605 // Third fill all context locals.
10606 Handle<Context> frame_context(Context::cast(frame->context()));
10607 Handle<Context> function_context(frame_context->declaration_context());
10608 if (!CopyContextLocalsToScopeObject(isolate,
10609 serialized_scope_info, scope_info,
10610 function_context, local_scope)) {
10611 return Handle<JSObject>();
10612 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010613
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010614 // Finally copy any properties from the function context extension.
10615 // These will be variables introduced by eval.
10616 if (function_context->closure() == *function) {
10617 if (function_context->has_extension() &&
10618 !function_context->IsGlobalContext()) {
10619 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
10620 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
10621 for (int i = 0; i < keys->length(); i++) {
10622 // Names of variables introduced by eval are strings.
10623 ASSERT(keys->get(i)->IsString());
10624 Handle<String> key(String::cast(keys->get(i)));
10625 RETURN_IF_EMPTY_HANDLE_VALUE(
10626 isolate,
10627 SetProperty(local_scope,
10628 key,
10629 GetProperty(ext, key),
10630 NONE,
10631 kNonStrictMode),
10632 Handle<JSObject>());
10633 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010634 }
10635 }
10636 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010637
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010638 return local_scope;
10639}
10640
10641
10642// Create a plain JSObject which materializes the closure content for the
10643// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010644static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10645 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010646 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010647
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010648 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010649 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10650 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010651
10652 // Allocate and initialize a JSObject with all the content of theis function
10653 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010654 Handle<JSObject> closure_scope =
10655 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010656
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010657 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010658 if (!CopyContextLocalsToScopeObject(isolate,
10659 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010660 context, closure_scope)) {
10661 return Handle<JSObject>();
10662 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010663
10664 // Finally copy any properties from the function context extension. This will
10665 // be variables introduced by eval.
10666 if (context->has_extension()) {
10667 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010668 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010669 for (int i = 0; i < keys->length(); i++) {
10670 // Names of variables introduced by eval are strings.
10671 ASSERT(keys->get(i)->IsString());
10672 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010673 RETURN_IF_EMPTY_HANDLE_VALUE(
10674 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010675 SetProperty(closure_scope,
10676 key,
10677 GetProperty(ext, key),
10678 NONE,
10679 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010680 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010681 }
10682 }
10683
10684 return closure_scope;
10685}
10686
10687
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010688// Create a plain JSObject which materializes the scope for the specified
10689// catch context.
10690static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10691 Handle<Context> context) {
10692 ASSERT(context->IsCatchContext());
10693 Handle<String> name(String::cast(context->extension()));
10694 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10695 Handle<JSObject> catch_scope =
10696 isolate->factory()->NewJSObject(isolate->object_function());
10697 RETURN_IF_EMPTY_HANDLE_VALUE(
10698 isolate,
10699 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10700 Handle<JSObject>());
10701 return catch_scope;
10702}
10703
10704
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010705// Create a plain JSObject which materializes the block scope for the specified
10706// block context.
10707static Handle<JSObject> MaterializeBlockScope(
10708 Isolate* isolate,
10709 Handle<Context> context) {
10710 ASSERT(context->IsBlockContext());
10711 Handle<SerializedScopeInfo> serialized_scope_info(
10712 SerializedScopeInfo::cast(context->extension()));
10713 ScopeInfo<> scope_info(*serialized_scope_info);
10714
10715 // Allocate and initialize a JSObject with all the arguments, stack locals
10716 // heap locals and extension properties of the debugged function.
10717 Handle<JSObject> block_scope =
10718 isolate->factory()->NewJSObject(isolate->object_function());
10719
10720 // Fill all context locals.
10721 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10722 if (!CopyContextLocalsToScopeObject(isolate,
10723 serialized_scope_info, scope_info,
10724 context, block_scope)) {
10725 return Handle<JSObject>();
10726 }
10727 }
10728
10729 return block_scope;
10730}
10731
10732
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010733// Iterate over the actual scopes visible from a stack frame. All scopes are
10734// backed by an actual context except the local scope, which is inserted
10735// "artifically" in the context chain.
10736class ScopeIterator {
10737 public:
10738 enum ScopeType {
10739 ScopeTypeGlobal = 0,
10740 ScopeTypeLocal,
10741 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010742 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010743 ScopeTypeCatch,
10744 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010745 };
10746
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010747 ScopeIterator(Isolate* isolate,
10748 JavaScriptFrame* frame,
10749 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010750 : isolate_(isolate),
10751 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010752 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010753 function_(JSFunction::cast(frame->function())),
10754 context_(Context::cast(frame->context())),
10755 local_done_(false),
10756 at_local_(false) {
10757
10758 // Check whether the first scope is actually a local scope.
10759 if (context_->IsGlobalContext()) {
10760 // If there is a stack slot for .result then this local scope has been
10761 // created for evaluating top level code and it is not a real local scope.
10762 // Checking for the existence of .result seems fragile, but the scope info
10763 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010764 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010765 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010766 at_local_ = index < 0;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010767 } else if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010768 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010769 } else if (context_->closure() != *function_) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010770 // The context_ is a block or with or catch block from the outer function.
10771 ASSERT(context_->IsWithContext() ||
10772 context_->IsCatchContext() ||
10773 context_->IsBlockContext());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010774 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010775 }
10776 }
10777
10778 // More scopes?
10779 bool Done() { return context_.is_null(); }
10780
10781 // Move to the next scope.
10782 void Next() {
10783 // If at a local scope mark the local scope as passed.
10784 if (at_local_) {
10785 at_local_ = false;
10786 local_done_ = true;
10787
10788 // If the current context is not associated with the local scope the
10789 // current context is the next real scope, so don't move to the next
10790 // context in this case.
10791 if (context_->closure() != *function_) {
10792 return;
10793 }
10794 }
10795
10796 // The global scope is always the last in the chain.
10797 if (context_->IsGlobalContext()) {
10798 context_ = Handle<Context>();
10799 return;
10800 }
10801
10802 // Move to the next context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010803 context_ = Handle<Context>(context_->previous(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010804
10805 // If passing the local scope indicate that the current scope is now the
10806 // local scope.
10807 if (!local_done_ &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010808 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010809 at_local_ = true;
10810 }
10811 }
10812
10813 // Return the type of the current scope.
10814 int Type() {
10815 if (at_local_) {
10816 return ScopeTypeLocal;
10817 }
10818 if (context_->IsGlobalContext()) {
10819 ASSERT(context_->global()->IsGlobalObject());
10820 return ScopeTypeGlobal;
10821 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010822 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010823 return ScopeTypeClosure;
10824 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010825 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010826 return ScopeTypeCatch;
10827 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010828 if (context_->IsBlockContext()) {
10829 return ScopeTypeBlock;
10830 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010831 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010832 return ScopeTypeWith;
10833 }
10834
10835 // Return the JavaScript object with the content of the current scope.
10836 Handle<JSObject> ScopeObject() {
10837 switch (Type()) {
10838 case ScopeIterator::ScopeTypeGlobal:
10839 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010840 case ScopeIterator::ScopeTypeLocal:
10841 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010842 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010843 case ScopeIterator::ScopeTypeWith:
10844 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010845 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
10846 case ScopeIterator::ScopeTypeCatch:
10847 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010848 case ScopeIterator::ScopeTypeClosure:
10849 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010850 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010851 case ScopeIterator::ScopeTypeBlock:
10852 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010853 }
10854 UNREACHABLE();
10855 return Handle<JSObject>();
10856 }
10857
10858 // Return the context for this scope. For the local context there might not
10859 // be an actual context.
10860 Handle<Context> CurrentContext() {
10861 if (at_local_ && context_->closure() != *function_) {
10862 return Handle<Context>();
10863 }
10864 return context_;
10865 }
10866
10867#ifdef DEBUG
10868 // Debug print of the content of the current scope.
10869 void DebugPrint() {
10870 switch (Type()) {
10871 case ScopeIterator::ScopeTypeGlobal:
10872 PrintF("Global:\n");
10873 CurrentContext()->Print();
10874 break;
10875
10876 case ScopeIterator::ScopeTypeLocal: {
10877 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010878 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010879 scope_info.Print();
10880 if (!CurrentContext().is_null()) {
10881 CurrentContext()->Print();
10882 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010883 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010884 if (extension->IsJSContextExtensionObject()) {
10885 extension->Print();
10886 }
10887 }
10888 }
10889 break;
10890 }
10891
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010892 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010893 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010894 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010895 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010896
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010897 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010898 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010899 CurrentContext()->extension()->Print();
10900 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010901 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010902
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010903 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010904 PrintF("Closure:\n");
10905 CurrentContext()->Print();
10906 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010907 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010908 if (extension->IsJSContextExtensionObject()) {
10909 extension->Print();
10910 }
10911 }
10912 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010913
10914 default:
10915 UNREACHABLE();
10916 }
10917 PrintF("\n");
10918 }
10919#endif
10920
10921 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010922 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010923 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010924 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010925 Handle<JSFunction> function_;
10926 Handle<Context> context_;
10927 bool local_done_;
10928 bool at_local_;
10929
10930 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10931};
10932
10933
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010934RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010935 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010936 ASSERT(args.length() == 2);
10937
10938 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010939 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010940 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10941 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010942 if (!maybe_check->ToObject(&check)) return maybe_check;
10943 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010944 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10945
10946 // Get the frame where the debugging is performed.
10947 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010948 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010949 JavaScriptFrame* frame = it.frame();
10950
10951 // Count the visible scopes.
10952 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010953 for (ScopeIterator it(isolate, frame, 0);
10954 !it.Done();
10955 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010956 n++;
10957 }
10958
10959 return Smi::FromInt(n);
10960}
10961
10962
10963static const int kScopeDetailsTypeIndex = 0;
10964static const int kScopeDetailsObjectIndex = 1;
10965static const int kScopeDetailsSize = 2;
10966
10967// Return an array with scope details
10968// args[0]: number: break id
10969// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010970// args[2]: number: inlined frame index
10971// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010972//
10973// The array returned contains the following information:
10974// 0: Scope type
10975// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010976RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010977 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010978 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010979
10980 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010981 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010982 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10983 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010984 if (!maybe_check->ToObject(&check)) return maybe_check;
10985 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010986 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010987 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
10988 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010989
10990 // Get the frame where the debugging is performed.
10991 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010992 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010993 JavaScriptFrame* frame = frame_it.frame();
10994
10995 // Find the requested scope.
10996 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010997 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010998 for (; !it.Done() && n < index; it.Next()) {
10999 n++;
11000 }
11001 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011002 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011003 }
11004
11005 // Calculate the size of the result.
11006 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011007 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011008
11009 // Fill in scope details.
11010 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011011 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011012 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011013 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011014
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011015 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011016}
11017
11018
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011019RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011020 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011021 ASSERT(args.length() == 0);
11022
11023#ifdef DEBUG
11024 // Print the scopes for the top frame.
11025 StackFrameLocator locator;
11026 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011027 for (ScopeIterator it(isolate, frame, 0);
11028 !it.Done();
11029 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011030 it.DebugPrint();
11031 }
11032#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011033 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011034}
11035
11036
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011037RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011038 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011039 ASSERT(args.length() == 1);
11040
11041 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011042 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011043 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11044 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011045 if (!maybe_result->ToObject(&result)) return maybe_result;
11046 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011047
11048 // Count all archived V8 threads.
11049 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011050 for (ThreadState* thread =
11051 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011052 thread != NULL;
11053 thread = thread->Next()) {
11054 n++;
11055 }
11056
11057 // Total number of threads is current thread and archived threads.
11058 return Smi::FromInt(n + 1);
11059}
11060
11061
11062static const int kThreadDetailsCurrentThreadIndex = 0;
11063static const int kThreadDetailsThreadIdIndex = 1;
11064static const int kThreadDetailsSize = 2;
11065
11066// Return an array with thread details
11067// args[0]: number: break id
11068// args[1]: number: thread index
11069//
11070// The array returned contains the following information:
11071// 0: Is current thread?
11072// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011073RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011074 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011075 ASSERT(args.length() == 2);
11076
11077 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011078 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011079 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11080 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011081 if (!maybe_check->ToObject(&check)) return maybe_check;
11082 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011083 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11084
11085 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011086 Handle<FixedArray> details =
11087 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011088
11089 // Thread index 0 is current thread.
11090 if (index == 0) {
11091 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011092 details->set(kThreadDetailsCurrentThreadIndex,
11093 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011094 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011095 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011096 } else {
11097 // Find the thread with the requested index.
11098 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011099 ThreadState* thread =
11100 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011101 while (index != n && thread != NULL) {
11102 thread = thread->Next();
11103 n++;
11104 }
11105 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011106 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011107 }
11108
11109 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011110 details->set(kThreadDetailsCurrentThreadIndex,
11111 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011112 details->set(kThreadDetailsThreadIdIndex,
11113 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011114 }
11115
11116 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011117 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011118}
11119
11120
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011121// Sets the disable break state
11122// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011123RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011124 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011125 ASSERT(args.length() == 1);
11126 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011127 isolate->debug()->set_disable_break(disable_break);
11128 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011129}
11130
11131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011132RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011133 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011134 ASSERT(args.length() == 1);
11135
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011136 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11137 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011138 // Find the number of break points
11139 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011140 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011141 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011142 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011143 Handle<FixedArray>::cast(break_locations));
11144}
11145
11146
11147// Set a break point in a function
11148// args[0]: function
11149// args[1]: number: break source position (within the function source)
11150// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011151RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011152 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011153 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011154 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11155 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011156 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11157 RUNTIME_ASSERT(source_position >= 0);
11158 Handle<Object> break_point_object_arg = args.at<Object>(2);
11159
11160 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011161 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11162 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011163
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011164 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011165}
11166
11167
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011168Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11169 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011170 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011171 // Iterate the heap looking for SharedFunctionInfo generated from the
11172 // script. The inner most SharedFunctionInfo containing the source position
11173 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011174 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011175 // which is found is not compiled it is compiled and the heap is iterated
11176 // again as the compilation might create inner functions from the newly
11177 // compiled function and the actual requested break point might be in one of
11178 // these functions.
11179 bool done = false;
11180 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011181 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011182 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011183 while (!done) {
11184 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011185 for (HeapObject* obj = iterator.next();
11186 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011187 if (obj->IsSharedFunctionInfo()) {
11188 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11189 if (shared->script() == *script) {
11190 // If the SharedFunctionInfo found has the requested script data and
11191 // contains the source position it is a candidate.
11192 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000011193 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011194 start_position = shared->start_position();
11195 }
11196 if (start_position <= position &&
11197 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000011198 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011199 // candidate this is the new candidate.
11200 if (target.is_null()) {
11201 target_start_position = start_position;
11202 target = shared;
11203 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011204 if (target_start_position == start_position &&
11205 shared->end_position() == target->end_position()) {
11206 // If a top-level function contain only one function
11207 // declartion the source for the top-level and the function is
11208 // the same. In that case prefer the non top-level function.
11209 if (!shared->is_toplevel()) {
11210 target_start_position = start_position;
11211 target = shared;
11212 }
11213 } else if (target_start_position <= start_position &&
11214 shared->end_position() <= target->end_position()) {
11215 // This containment check includes equality as a function inside
11216 // a top-level function can share either start or end position
11217 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011218 target_start_position = start_position;
11219 target = shared;
11220 }
11221 }
11222 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011223 }
11224 }
11225 }
11226
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011227 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011228 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011229 }
11230
11231 // If the candidate found is compiled we are done. NOTE: when lazy
11232 // compilation of inner functions is introduced some additional checking
11233 // needs to be done here to compile inner functions.
11234 done = target->is_compiled();
11235 if (!done) {
11236 // If the candidate is not compiled compile it to reveal any inner
11237 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011238 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011239 }
11240 }
11241
11242 return *target;
11243}
11244
11245
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011246// Changes the state of a break point in a script and returns source position
11247// where break point was set. NOTE: Regarding performance see the NOTE for
11248// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011249// args[0]: script to set break point in
11250// args[1]: number: break source position (within the script source)
11251// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011252RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011253 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011254 ASSERT(args.length() == 3);
11255 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11256 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11257 RUNTIME_ASSERT(source_position >= 0);
11258 Handle<Object> break_point_object_arg = args.at<Object>(2);
11259
11260 // Get the script from the script wrapper.
11261 RUNTIME_ASSERT(wrapper->value()->IsScript());
11262 Handle<Script> script(Script::cast(wrapper->value()));
11263
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011264 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011265 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011266 if (!result->IsUndefined()) {
11267 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11268 // Find position within function. The script position might be before the
11269 // source position of the first function.
11270 int position;
11271 if (shared->start_position() > source_position) {
11272 position = 0;
11273 } else {
11274 position = source_position - shared->start_position();
11275 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011276 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011277 position += shared->start_position();
11278 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011279 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011280 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011281}
11282
11283
11284// Clear a break point
11285// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011286RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011287 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011288 ASSERT(args.length() == 1);
11289 Handle<Object> break_point_object_arg = args.at<Object>(0);
11290
11291 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011292 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011293
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011294 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// Change the state of break on exceptions.
11299// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11300// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011301RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011302 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011303 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011304 RUNTIME_ASSERT(args[0]->IsNumber());
11305 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011306
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011307 // If the number doesn't match an enum value, the ChangeBreakOnException
11308 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011309 ExceptionBreakType type =
11310 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011311 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011312 isolate->debug()->ChangeBreakOnException(type, enable);
11313 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011314}
11315
11316
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011317// Returns the state of break on exceptions
11318// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011319RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011320 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011321 ASSERT(args.length() == 1);
11322 RUNTIME_ASSERT(args[0]->IsNumber());
11323
11324 ExceptionBreakType type =
11325 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011326 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011327 return Smi::FromInt(result);
11328}
11329
11330
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011331// Prepare for stepping
11332// args[0]: break id for checking execution state
11333// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011334// args[2]: number of times to perform the step, for step out it is the number
11335// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011336RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011337 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011338 ASSERT(args.length() == 3);
11339 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011340 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011341 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11342 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011343 if (!maybe_check->ToObject(&check)) return maybe_check;
11344 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011345 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011346 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011347 }
11348
11349 // Get the step action and check validity.
11350 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11351 if (step_action != StepIn &&
11352 step_action != StepNext &&
11353 step_action != StepOut &&
11354 step_action != StepInMin &&
11355 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011356 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011357 }
11358
11359 // Get the number of steps.
11360 int step_count = NumberToInt32(args[2]);
11361 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011362 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011363 }
11364
ager@chromium.orga1645e22009-09-09 19:27:10 +000011365 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011366 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011367
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011368 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011369 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11370 step_count);
11371 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011372}
11373
11374
11375// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011376RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011377 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011378 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011379 isolate->debug()->ClearStepping();
11380 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011381}
11382
11383
11384// Creates a copy of the with context chain. The copy of the context chain is
11385// is linked to the function context supplied.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011386static Handle<Context> CopyWithContextChain(Isolate* isolate,
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011387 Handle<JSFunction> function,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011388 Handle<Context> current,
11389 Handle<Context> base) {
11390 // At the end of the chain. Return the base context to link to.
11391 if (current->IsFunctionContext() || current->IsGlobalContext()) {
11392 return base;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011393 }
11394
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011395 // Recursively copy the with and catch contexts.
11396 HandleScope scope(isolate);
11397 Handle<Context> previous(current->previous());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011398 Handle<Context> new_previous =
11399 CopyWithContextChain(isolate, function, previous, base);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011400 Handle<Context> new_current;
11401 if (current->IsCatchContext()) {
11402 Handle<String> name(String::cast(current->extension()));
11403 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11404 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011405 isolate->factory()->NewCatchContext(function,
11406 new_previous,
11407 name,
11408 thrown_object);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011409 } else if (current->IsBlockContext()) {
11410 Handle<SerializedScopeInfo> scope_info(
11411 SerializedScopeInfo::cast(current->extension()));
11412 new_current =
11413 isolate->factory()->NewBlockContext(function, new_previous, scope_info);
danno@chromium.orgb6451162011-08-17 14:33:23 +000011414 // Copy context slots.
11415 int num_context_slots = scope_info->NumberOfContextSlots();
11416 for (int i = Context::MIN_CONTEXT_SLOTS; i < num_context_slots; ++i) {
11417 new_current->set(i, current->get(i));
11418 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011419 } else {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011420 ASSERT(current->IsWithContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011421 Handle<JSObject> extension(JSObject::cast(current->extension()));
11422 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011423 isolate->factory()->NewWithContext(function, new_previous, extension);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011424 }
11425 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011426}
11427
11428
11429// Helper function to find or create the arguments object for
11430// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011431static Handle<Object> GetArgumentsObject(Isolate* isolate,
11432 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011433 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011434 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011435 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011436 const ScopeInfo<>* sinfo,
11437 Handle<Context> function_context) {
11438 // Try to find the value of 'arguments' to pass as parameter. If it is not
11439 // found (that is the debugged function does not reference 'arguments' and
11440 // does not support eval) then create an 'arguments' object.
11441 int index;
11442 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011443 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011444 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011445 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011446 }
11447 }
11448
11449 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011450 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
11451 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011452 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011453 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011454 }
11455 }
11456
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011457 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
11458
11459 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011460 Handle<JSObject> arguments =
11461 isolate->factory()->NewArgumentsObject(function, length);
11462 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011463
11464 AssertNoAllocation no_gc;
11465 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011466 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011467 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011468 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011469 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011470 return arguments;
11471}
11472
11473
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011474static const char kSourceStr[] =
11475 "(function(arguments,__source__){return eval(__source__);})";
11476
11477
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011478// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011479// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011480// extension part has all the parameters and locals of the function on the
11481// stack frame. A function which calls eval with the code to evaluate is then
11482// compiled in this context and called in this context. As this context
11483// replaces the context of the function on the stack frame a new (empty)
11484// function is created as well to be used as the closure for the context.
11485// This function and the context acts as replacements for the function on the
11486// stack frame presenting the same view of the values of parameters and
11487// local variables as if the piece of JavaScript was evaluated at the point
11488// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011489RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011490 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011491
11492 // Check the execution state and decode arguments frame and source to be
11493 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011494 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011495 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011496 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11497 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011498 if (!maybe_check_result->ToObject(&check_result)) {
11499 return maybe_check_result;
11500 }
11501 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011502 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011503 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11504 CONVERT_ARG_CHECKED(String, source, 3);
11505 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
11506 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011507
11508 // Handle the processing of break.
11509 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011510
11511 // Get the frame where the debugging is performed.
11512 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011513 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011514 JavaScriptFrame* frame = it.frame();
11515 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000011516 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011517 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011518
11519 // Traverse the saved contexts chain to find the active context for the
11520 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011521 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011522 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011523 save = save->prev();
11524 }
11525 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011526 SaveContext savex(isolate);
11527 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011528
11529 // Create the (empty) function replacing the function on the stack frame for
11530 // the purpose of evaluating in the context created below. It is important
11531 // that this function does not describe any parameters and local variables
11532 // in the context. If it does then this will cause problems with the lookup
11533 // in Context::Lookup, where context slots for parameters and local variables
11534 // are looked at before the extension object.
11535 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011536 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11537 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011538 go_between->set_context(function->context());
11539#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011540 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011541 ASSERT(go_between_sinfo.number_of_parameters() == 0);
11542 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
11543#endif
11544
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011545 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011546 Handle<JSObject> local_scope = MaterializeLocalScope(
11547 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011548 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011549
11550 // Allocate a new context for the debug evaluation and set the extension
11551 // object build.
11552 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011553 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11554 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011555 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011556 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011557 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011558 Handle<Context> function_context;
11559 // Get the function's context if it has one.
11560 if (scope_info->HasHeapAllocatedLocals()) {
11561 function_context = Handle<Context>(frame_context->declaration_context());
11562 }
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011563 context = CopyWithContextChain(isolate, go_between, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011564
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011565 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011566 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011567 context =
11568 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011569 }
11570
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011571 // Wrap the evaluation statement in a new function compiled in the newly
11572 // created context. The function has one parameter which has to be called
11573 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011574 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011575 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011576
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011577 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011578 isolate->factory()->NewStringFromAscii(
11579 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011580
11581 // Currently, the eval code will be executed in non-strict mode,
11582 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011583 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011584 Compiler::CompileEval(function_source,
11585 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011586 context->IsGlobalContext(),
11587 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011588 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011589 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011590 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011591
11592 // Invoke the result of the compilation to get the evaluation function.
11593 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011594 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011595 Handle<Object> evaluation_function =
11596 Execution::Call(compiled_function, receiver, 0, NULL,
11597 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011598 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011599
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011600 Handle<Object> arguments = GetArgumentsObject(isolate,
11601 frame, inlined_frame_index,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011602 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011603 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011604
11605 // Invoke the evaluation function and return the result.
11606 const int argc = 2;
11607 Object** argv[argc] = { arguments.location(),
11608 Handle<Object>::cast(source).location() };
11609 Handle<Object> result =
11610 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11611 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011612 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011613
11614 // Skip the global proxy as it has no properties and always delegates to the
11615 // real global object.
11616 if (result->IsJSGlobalProxy()) {
11617 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11618 }
11619
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011620 return *result;
11621}
11622
11623
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011624RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011625 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011626
11627 // Check the execution state and decode arguments frame and source to be
11628 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011629 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011630 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011631 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11632 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011633 if (!maybe_check_result->ToObject(&check_result)) {
11634 return maybe_check_result;
11635 }
11636 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011637 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011638 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011639 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011640
11641 // Handle the processing of break.
11642 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011643
11644 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011645 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011646 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011647 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011648 top = top->prev();
11649 }
11650 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011651 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011652 }
11653
11654 // Get the global context now set to the top context from before the
11655 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011656 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011657
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011658 bool is_global = true;
11659
11660 if (additional_context->IsJSObject()) {
11661 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011662 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11663 isolate->factory()->empty_string(),
11664 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011665 go_between->set_context(*context);
11666 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011667 isolate->factory()->NewFunctionContext(
11668 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011669 context->set_extension(JSObject::cast(*additional_context));
11670 is_global = false;
11671 }
11672
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011673 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011674 // Currently, the eval code will be executed in non-strict mode,
11675 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011676 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011677 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011678 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011679 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011680 Handle<JSFunction>(
11681 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11682 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011683
11684 // Invoke the result of the compilation to get the evaluation function.
11685 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011686 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011687 Handle<Object> result =
11688 Execution::Call(compiled_function, receiver, 0, NULL,
11689 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011690 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011691 return *result;
11692}
11693
11694
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011695RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011696 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011697 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011698
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011699 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011700 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011701
11702 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011703 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011704 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11705 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11706 // because using
11707 // instances->set(i, *GetScriptWrapper(script))
11708 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11709 // already have deferenced the instances handle.
11710 Handle<JSValue> wrapper = GetScriptWrapper(script);
11711 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011712 }
11713
11714 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011715 Handle<JSObject> result =
11716 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011717 Handle<JSArray>::cast(result)->SetContent(*instances);
11718 return *result;
11719}
11720
11721
11722// Helper function used by Runtime_DebugReferencedBy below.
11723static int DebugReferencedBy(JSObject* target,
11724 Object* instance_filter, int max_references,
11725 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011726 JSFunction* arguments_function) {
11727 NoHandleAllocation ha;
11728 AssertNoAllocation no_alloc;
11729
11730 // Iterate the heap.
11731 int count = 0;
11732 JSObject* last = NULL;
11733 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011734 HeapObject* heap_obj = NULL;
11735 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011736 (max_references == 0 || count < max_references)) {
11737 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011738 if (heap_obj->IsJSObject()) {
11739 // Skip context extension objects and argument arrays as these are
11740 // checked in the context of functions using them.
11741 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011742 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011743 obj->map()->constructor() == arguments_function) {
11744 continue;
11745 }
11746
11747 // Check if the JS object has a reference to the object looked for.
11748 if (obj->ReferencesObject(target)) {
11749 // Check instance filter if supplied. This is normally used to avoid
11750 // references from mirror objects (see Runtime_IsInPrototypeChain).
11751 if (!instance_filter->IsUndefined()) {
11752 Object* V = obj;
11753 while (true) {
11754 Object* prototype = V->GetPrototype();
11755 if (prototype->IsNull()) {
11756 break;
11757 }
11758 if (instance_filter == prototype) {
11759 obj = NULL; // Don't add this object.
11760 break;
11761 }
11762 V = prototype;
11763 }
11764 }
11765
11766 if (obj != NULL) {
11767 // Valid reference found add to instance array if supplied an update
11768 // count.
11769 if (instances != NULL && count < instances_size) {
11770 instances->set(count, obj);
11771 }
11772 last = obj;
11773 count++;
11774 }
11775 }
11776 }
11777 }
11778
11779 // Check for circular reference only. This can happen when the object is only
11780 // referenced from mirrors and has a circular reference in which case the
11781 // object is not really alive and would have been garbage collected if not
11782 // referenced from the mirror.
11783 if (count == 1 && last == target) {
11784 count = 0;
11785 }
11786
11787 // Return the number of referencing objects found.
11788 return count;
11789}
11790
11791
11792// Scan the heap for objects with direct references to an object
11793// args[0]: the object to find references to
11794// args[1]: constructor function for instances to exclude (Mirror)
11795// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011796RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011797 ASSERT(args.length() == 3);
11798
11799 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011800 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011801
11802 // Check parameters.
11803 CONVERT_CHECKED(JSObject, target, args[0]);
11804 Object* instance_filter = args[1];
11805 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11806 instance_filter->IsJSObject());
11807 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11808 RUNTIME_ASSERT(max_references >= 0);
11809
11810 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011811 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011812 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011813 JSFunction* arguments_function =
11814 JSFunction::cast(arguments_boilerplate->map()->constructor());
11815
11816 // Get the number of referencing objects.
11817 int count;
11818 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011819 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011820
11821 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011822 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011823 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011824 if (!maybe_object->ToObject(&object)) return maybe_object;
11825 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011826 FixedArray* instances = FixedArray::cast(object);
11827
11828 // Fill the referencing objects.
11829 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011830 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011831
11832 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011833 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011834 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11835 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011836 if (!maybe_result->ToObject(&result)) return maybe_result;
11837 }
11838 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011839 return result;
11840}
11841
11842
11843// Helper function used by Runtime_DebugConstructedBy below.
11844static int DebugConstructedBy(JSFunction* constructor, int max_references,
11845 FixedArray* instances, int instances_size) {
11846 AssertNoAllocation no_alloc;
11847
11848 // Iterate the heap.
11849 int count = 0;
11850 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011851 HeapObject* heap_obj = NULL;
11852 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011853 (max_references == 0 || count < max_references)) {
11854 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011855 if (heap_obj->IsJSObject()) {
11856 JSObject* obj = JSObject::cast(heap_obj);
11857 if (obj->map()->constructor() == constructor) {
11858 // Valid reference found add to instance array if supplied an update
11859 // count.
11860 if (instances != NULL && count < instances_size) {
11861 instances->set(count, obj);
11862 }
11863 count++;
11864 }
11865 }
11866 }
11867
11868 // Return the number of referencing objects found.
11869 return count;
11870}
11871
11872
11873// Scan the heap for objects constructed by a specific function.
11874// args[0]: the constructor to find instances of
11875// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011876RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011877 ASSERT(args.length() == 2);
11878
11879 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011880 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011881
11882 // Check parameters.
11883 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11884 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11885 RUNTIME_ASSERT(max_references >= 0);
11886
11887 // Get the number of referencing objects.
11888 int count;
11889 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11890
11891 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011892 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011893 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011894 if (!maybe_object->ToObject(&object)) return maybe_object;
11895 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011896 FixedArray* instances = FixedArray::cast(object);
11897
11898 // Fill the referencing objects.
11899 count = DebugConstructedBy(constructor, max_references, instances, count);
11900
11901 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011902 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011903 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11904 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011905 if (!maybe_result->ToObject(&result)) return maybe_result;
11906 }
11907 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011908 return result;
11909}
11910
11911
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011912// Find the effective prototype object as returned by __proto__.
11913// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011914RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011915 ASSERT(args.length() == 1);
11916
11917 CONVERT_CHECKED(JSObject, obj, args[0]);
11918
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011919 // Use the __proto__ accessor.
11920 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011921}
11922
11923
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011924RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011925 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011926 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011927 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011928}
11929
11930
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011931RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011932#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011933 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011934 ASSERT(args.length() == 1);
11935 // Get the function and make sure it is compiled.
11936 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011937 Handle<SharedFunctionInfo> shared(func->shared());
11938 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011939 return Failure::Exception();
11940 }
11941 func->code()->PrintLn();
11942#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011943 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011944}
ager@chromium.org9085a012009-05-11 19:22:57 +000011945
11946
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011947RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011948#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011949 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011950 ASSERT(args.length() == 1);
11951 // Get the function and make sure it is compiled.
11952 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011953 Handle<SharedFunctionInfo> shared(func->shared());
11954 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011955 return Failure::Exception();
11956 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011957 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011958#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011959 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011960}
11961
11962
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011963RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011964 NoHandleAllocation ha;
11965 ASSERT(args.length() == 1);
11966
11967 CONVERT_CHECKED(JSFunction, f, args[0]);
11968 return f->shared()->inferred_name();
11969}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011970
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011971
11972static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011973 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011974 AssertNoAllocation no_allocations;
11975
11976 int counter = 0;
11977 int buffer_size = buffer->length();
11978 HeapIterator iterator;
11979 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11980 ASSERT(obj != NULL);
11981 if (!obj->IsSharedFunctionInfo()) {
11982 continue;
11983 }
11984 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11985 if (shared->script() != script) {
11986 continue;
11987 }
11988 if (counter < buffer_size) {
11989 buffer->set(counter, shared);
11990 }
11991 counter++;
11992 }
11993 return counter;
11994}
11995
11996// For a script finds all SharedFunctionInfo's in the heap that points
11997// to this script. Returns JSArray of SharedFunctionInfo wrapped
11998// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011999RUNTIME_FUNCTION(MaybeObject*,
12000 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012001 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012002 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012003 CONVERT_CHECKED(JSValue, script_value, args[0]);
12004
12005 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12006
12007 const int kBufferSize = 32;
12008
12009 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012010 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012011 int number = FindSharedFunctionInfosForScript(*script, *array);
12012 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012013 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012014 FindSharedFunctionInfosForScript(*script, *array);
12015 }
12016
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012017 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012018 result->set_length(Smi::FromInt(number));
12019
12020 LiveEdit::WrapSharedFunctionInfos(result);
12021
12022 return *result;
12023}
12024
12025// For a script calculates compilation information about all its functions.
12026// The script source is explicitly specified by the second argument.
12027// The source of the actual script is not used, however it is important that
12028// all generated code keeps references to this particular instance of script.
12029// Returns a JSArray of compilation infos. The array is ordered so that
12030// each function with all its descendant is always stored in a continues range
12031// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012032RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012033 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012034 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012035 CONVERT_CHECKED(JSValue, script, args[0]);
12036 CONVERT_ARG_CHECKED(String, source, 1);
12037 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12038
12039 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12040
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012041 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012042 return Failure::Exception();
12043 }
12044
12045 return result;
12046}
12047
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012048// Changes the source of the script to a new_source.
12049// If old_script_name is provided (i.e. is a String), also creates a copy of
12050// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012051RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012052 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012053 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012054 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12055 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012056 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012057
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012058 CONVERT_CHECKED(Script, original_script_pointer,
12059 original_script_value->value());
12060 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012061
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012062 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12063 new_source,
12064 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012065
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012066 if (old_script->IsScript()) {
12067 Handle<Script> script_handle(Script::cast(old_script));
12068 return *(GetScriptWrapper(script_handle));
12069 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012070 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012071 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012072}
12073
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012074
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012075RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012076 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012077 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012078 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12079 return LiveEdit::FunctionSourceUpdated(shared_info);
12080}
12081
12082
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012083// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012084RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012085 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012086 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012087 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12088 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12089
ager@chromium.orgac091b72010-05-05 07:34:42 +000012090 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012091}
12092
12093// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012094RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012095 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012096 HandleScope scope(isolate);
12097 Handle<Object> function_object(args[0], isolate);
12098 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012099
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012100 if (function_object->IsJSValue()) {
12101 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12102 if (script_object->IsJSValue()) {
12103 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012104 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012105 }
12106
12107 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12108 } else {
12109 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12110 // and we check it in this function.
12111 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012112
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012113 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012114}
12115
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012116
12117// In a code of a parent function replaces original function as embedded object
12118// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012119RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012120 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012121 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012122
12123 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12124 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12125 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12126
12127 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12128 subst_wrapper);
12129
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012130 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012131}
12132
12133
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012134// Updates positions of a shared function info (first parameter) according
12135// to script source change. Text change is described in second parameter as
12136// array of groups of 3 numbers:
12137// (change_begin, change_end, change_end_new_position).
12138// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012139RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012140 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012141 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012142 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12143 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12144
ager@chromium.orgac091b72010-05-05 07:34:42 +000012145 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012146}
12147
12148
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012149// For array of SharedFunctionInfo's (each wrapped in JSValue)
12150// checks that none of them have activations on stacks (of any thread).
12151// Returns array of the same length with corresponding results of
12152// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012153RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012154 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012155 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012156 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012157 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012158
ager@chromium.org357bf652010-04-12 11:30:10 +000012159 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012160}
12161
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012162// Compares 2 strings line-by-line, then token-wise and returns diff in form
12163// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12164// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012165RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012166 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012167 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012168 CONVERT_ARG_CHECKED(String, s1, 0);
12169 CONVERT_ARG_CHECKED(String, s2, 1);
12170
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012171 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012172}
12173
12174
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012175// A testing entry. Returns statement position which is the closest to
12176// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012177RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012178 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012179 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012180 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12181 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12182
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012183 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012184
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012185 if (code->kind() != Code::FUNCTION &&
12186 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012187 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012188 }
12189
12190 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012191 int closest_pc = 0;
12192 int distance = kMaxInt;
12193 while (!it.done()) {
12194 int statement_position = static_cast<int>(it.rinfo()->data());
12195 // Check if this break point is closer that what was previously found.
12196 if (source_position <= statement_position &&
12197 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012198 closest_pc =
12199 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012200 distance = statement_position - source_position;
12201 // Check whether we can't get any closer.
12202 if (distance == 0) break;
12203 }
12204 it.next();
12205 }
12206
12207 return Smi::FromInt(closest_pc);
12208}
12209
12210
ager@chromium.org357bf652010-04-12 11:30:10 +000012211// Calls specified function with or without entering the debugger.
12212// This is used in unit tests to run code as if debugger is entered or simply
12213// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012214RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012215 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012216 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012217 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12218 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12219
12220 Handle<Object> result;
12221 bool pending_exception;
12222 {
12223 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012224 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012225 &pending_exception);
12226 } else {
12227 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012228 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012229 &pending_exception);
12230 }
12231 }
12232 if (!pending_exception) {
12233 return *result;
12234 } else {
12235 return Failure::Exception();
12236 }
12237}
12238
12239
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012240// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012241RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012242 CONVERT_CHECKED(String, arg, args[0]);
12243 SmartPointer<char> flags =
12244 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12245 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012246 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012247}
12248
12249
12250// Performs a GC.
12251// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012252RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012253 isolate->heap()->CollectAllGarbage(true);
12254 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012255}
12256
12257
12258// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012259RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012260 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012261 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012262 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012263 }
12264 return Smi::FromInt(usage);
12265}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012266
12267
12268// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012269RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012270#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012271 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012272#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012273 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012274#endif
12275}
12276
12277
12278// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012279RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012280#ifdef LIVE_OBJECT_LIST
12281 return LiveObjectList::Capture();
12282#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012283 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012284#endif
12285}
12286
12287
12288// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012289RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012290#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012291 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012292 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012293 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012294#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012295 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012296#endif
12297}
12298
12299
12300// Generates the response to a debugger request for a dump of the objects
12301// contained in the difference between the captured live object lists
12302// specified by id1 and id2.
12303// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12304// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012305RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012306#ifdef LIVE_OBJECT_LIST
12307 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012308 CONVERT_SMI_ARG_CHECKED(id1, 0);
12309 CONVERT_SMI_ARG_CHECKED(id2, 1);
12310 CONVERT_SMI_ARG_CHECKED(start, 2);
12311 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012312 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12313 EnterDebugger enter_debugger;
12314 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12315#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012316 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012317#endif
12318}
12319
12320
12321// Gets the specified object as requested by the debugger.
12322// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012323RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012324#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012325 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012326 Object* result = LiveObjectList::GetObj(obj_id);
12327 return result;
12328#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012329 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012330#endif
12331}
12332
12333
12334// Gets the obj id for the specified address if valid.
12335// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012336RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012337#ifdef LIVE_OBJECT_LIST
12338 HandleScope scope;
12339 CONVERT_ARG_CHECKED(String, address, 0);
12340 Object* result = LiveObjectList::GetObjId(address);
12341 return result;
12342#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012343 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012344#endif
12345}
12346
12347
12348// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012349RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012350#ifdef LIVE_OBJECT_LIST
12351 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012352 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012353 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12354 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12355 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12356 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12357 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12358
12359 Handle<JSObject> instance_filter;
12360 if (args[1]->IsJSObject()) {
12361 instance_filter = args.at<JSObject>(1);
12362 }
12363 bool verbose = false;
12364 if (args[2]->IsBoolean()) {
12365 verbose = args[2]->IsTrue();
12366 }
12367 int start = 0;
12368 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012369 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012370 }
12371 int limit = Smi::kMaxValue;
12372 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012373 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012374 }
12375
12376 return LiveObjectList::GetObjRetainers(obj_id,
12377 instance_filter,
12378 verbose,
12379 start,
12380 limit,
12381 filter_obj);
12382#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012383 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012384#endif
12385}
12386
12387
12388// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012389RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012390#ifdef LIVE_OBJECT_LIST
12391 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012392 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12393 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012394 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12395
12396 Handle<JSObject> instance_filter;
12397 if (args[2]->IsJSObject()) {
12398 instance_filter = args.at<JSObject>(2);
12399 }
12400
12401 Object* result =
12402 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12403 return result;
12404#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012405 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012406#endif
12407}
12408
12409
12410// Generates the response to a debugger request for a list of all
12411// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012412RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012413#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012414 CONVERT_SMI_ARG_CHECKED(start, 0);
12415 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012416 return LiveObjectList::Info(start, count);
12417#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012418 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012419#endif
12420}
12421
12422
12423// Gets a dump of the specified object as requested by the debugger.
12424// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012425RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012426#ifdef LIVE_OBJECT_LIST
12427 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012428 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012429 Object* result = LiveObjectList::PrintObj(obj_id);
12430 return result;
12431#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012432 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012433#endif
12434}
12435
12436
12437// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012438RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012439#ifdef LIVE_OBJECT_LIST
12440 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012441 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012442#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012443 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012444#endif
12445}
12446
12447
12448// Generates the response to a debugger request for a summary of the types
12449// of objects in the difference between the captured live object lists
12450// specified by id1 and id2.
12451// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12452// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012453RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012454#ifdef LIVE_OBJECT_LIST
12455 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012456 CONVERT_SMI_ARG_CHECKED(id1, 0);
12457 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012458 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
12459
12460 EnterDebugger enter_debugger;
12461 return LiveObjectList::Summarize(id1, id2, filter_obj);
12462#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012463 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012464#endif
12465}
12466
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012467#endif // ENABLE_DEBUGGER_SUPPORT
12468
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012469
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012470RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012471 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012472 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012473 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012474}
12475
12476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012477RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012478 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012479 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012480 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012481}
12482
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012483
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012484// Finds the script object from the script data. NOTE: This operation uses
12485// heap traversal to find the function generated for the source position
12486// for the requested break point. For lazily compiled functions several heap
12487// traversals might be required rendering this operation as a rather slow
12488// operation. However for setting break points which is normally done through
12489// some kind of user interaction the performance is not crucial.
12490static Handle<Object> Runtime_GetScriptFromScriptName(
12491 Handle<String> script_name) {
12492 // Scan the heap for Script objects to find the script with the requested
12493 // script data.
12494 Handle<Script> script;
12495 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012496 HeapObject* obj = NULL;
12497 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012498 // If a script is found check if it has the script data requested.
12499 if (obj->IsScript()) {
12500 if (Script::cast(obj)->name()->IsString()) {
12501 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12502 script = Handle<Script>(Script::cast(obj));
12503 }
12504 }
12505 }
12506 }
12507
12508 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012509 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012510
12511 // Return the script found.
12512 return GetScriptWrapper(script);
12513}
12514
12515
12516// Get the script object from script data. NOTE: Regarding performance
12517// see the NOTE for GetScriptFromScriptData.
12518// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012519RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012520 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012521
12522 ASSERT(args.length() == 1);
12523
12524 CONVERT_CHECKED(String, script_name, args[0]);
12525
12526 // Find the requested script.
12527 Handle<Object> result =
12528 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12529 return *result;
12530}
12531
12532
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012533// Determines whether the given stack frame should be displayed in
12534// a stack trace. The caller is the error constructor that asked
12535// for the stack trace to be collected. The first time a construct
12536// call to this function is encountered it is skipped. The seen_caller
12537// in/out parameter is used to remember if the caller has been seen
12538// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012539static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12540 Object* caller,
12541 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012542 // Only display JS frames.
12543 if (!raw_frame->is_java_script())
12544 return false;
12545 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12546 Object* raw_fun = frame->function();
12547 // Not sure when this can happen but skip it just in case.
12548 if (!raw_fun->IsJSFunction())
12549 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012550 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012551 *seen_caller = true;
12552 return false;
12553 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012554 // Skip all frames until we've seen the caller.
12555 if (!(*seen_caller)) return false;
12556 // Also, skip the most obvious builtin calls. We recognize builtins
12557 // as (1) functions called with the builtins object as the receiver and
12558 // as (2) functions from native scripts called with undefined as the
12559 // receiver (direct calls to helper functions in the builtins
12560 // code). Some builtin calls (such as Number.ADD which is invoked
12561 // using 'call') are very difficult to recognize so we're leaving
12562 // them in for now.
12563 if (frame->receiver()->IsJSBuiltinsObject()) {
12564 return false;
12565 }
12566 JSFunction* fun = JSFunction::cast(raw_fun);
12567 Object* raw_script = fun->shared()->script();
12568 if (frame->receiver()->IsUndefined() && raw_script->IsScript()) {
12569 int script_type = Script::cast(raw_script)->type()->value();
12570 return script_type != Script::TYPE_NATIVE;
12571 }
12572 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012573}
12574
12575
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012576// Collect the raw data for a stack trace. Returns an array of 4
12577// element segments each containing a receiver, function, code and
12578// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012579RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012580 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012581 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012582 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12583
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012584 HandleScope scope(isolate);
12585 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012586
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012587 limit = Max(limit, 0); // Ensure that limit is not negative.
12588 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012589 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012590 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012591
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012592 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012593 // If the caller parameter is a function we skip frames until we're
12594 // under it before starting to collect.
12595 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012596 int cursor = 0;
12597 int frames_seen = 0;
12598 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012599 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012600 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012601 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012602 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012603 // Set initial size to the maximum inlining level + 1 for the outermost
12604 // function.
12605 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012606 frame->Summarize(&frames);
12607 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012608 if (cursor + 4 > elements->length()) {
12609 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12610 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012611 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012612 for (int i = 0; i < cursor; i++) {
12613 new_elements->set(i, elements->get(i));
12614 }
12615 elements = new_elements;
12616 }
12617 ASSERT(cursor + 4 <= elements->length());
12618
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012619 Handle<Object> recv = frames[i].receiver();
12620 Handle<JSFunction> fun = frames[i].function();
12621 Handle<Code> code = frames[i].code();
12622 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012623 elements->set(cursor++, *recv);
12624 elements->set(cursor++, *fun);
12625 elements->set(cursor++, *code);
12626 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012627 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012628 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012629 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012630 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012631 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012632 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012633 return *result;
12634}
12635
12636
ager@chromium.org3811b432009-10-28 14:53:37 +000012637// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012638RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012639 ASSERT_EQ(args.length(), 0);
12640
12641 NoHandleAllocation ha;
12642
12643 const char* version_string = v8::V8::GetVersion();
12644
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012645 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12646 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012647}
12648
12649
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012650RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012651 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012652 OS::PrintError("abort: %s\n",
12653 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012654 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012655 OS::Abort();
12656 UNREACHABLE();
12657 return NULL;
12658}
12659
12660
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012661RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012662 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012663 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012664 Object* key = args[1];
12665
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012666 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012667 Object* o = cache->get(finger_index);
12668 if (o == key) {
12669 // The fastest case: hit the same place again.
12670 return cache->get(finger_index + 1);
12671 }
12672
12673 for (int i = finger_index - 2;
12674 i >= JSFunctionResultCache::kEntriesIndex;
12675 i -= 2) {
12676 o = cache->get(i);
12677 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012678 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012679 return cache->get(i + 1);
12680 }
12681 }
12682
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012683 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012684 ASSERT(size <= cache->length());
12685
12686 for (int i = size - 2; i > finger_index; i -= 2) {
12687 o = cache->get(i);
12688 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012689 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012690 return cache->get(i + 1);
12691 }
12692 }
12693
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012694 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012695 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012696
12697 Handle<JSFunctionResultCache> cache_handle(cache);
12698 Handle<Object> key_handle(key);
12699 Handle<Object> value;
12700 {
12701 Handle<JSFunction> factory(JSFunction::cast(
12702 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12703 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012704 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012705 // This handle is nor shared, nor used later, so it's safe.
12706 Object** argv[] = { key_handle.location() };
12707 bool pending_exception = false;
12708 value = Execution::Call(factory,
12709 receiver,
12710 1,
12711 argv,
12712 &pending_exception);
12713 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012714 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012715
12716#ifdef DEBUG
12717 cache_handle->JSFunctionResultCacheVerify();
12718#endif
12719
12720 // Function invocation may have cleared the cache. Reread all the data.
12721 finger_index = cache_handle->finger_index();
12722 size = cache_handle->size();
12723
12724 // If we have spare room, put new data into it, otherwise evict post finger
12725 // entry which is likely to be the least recently used.
12726 int index = -1;
12727 if (size < cache_handle->length()) {
12728 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12729 index = size;
12730 } else {
12731 index = finger_index + JSFunctionResultCache::kEntrySize;
12732 if (index == cache_handle->length()) {
12733 index = JSFunctionResultCache::kEntriesIndex;
12734 }
12735 }
12736
12737 ASSERT(index % 2 == 0);
12738 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12739 ASSERT(index < cache_handle->length());
12740
12741 cache_handle->set(index, *key_handle);
12742 cache_handle->set(index + 1, *value);
12743 cache_handle->set_finger_index(index);
12744
12745#ifdef DEBUG
12746 cache_handle->JSFunctionResultCacheVerify();
12747#endif
12748
12749 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012750}
12751
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012752
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012753RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012754 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012755 CONVERT_ARG_CHECKED(String, type, 0);
12756 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012757 return *isolate->factory()->NewJSMessageObject(
12758 type,
12759 arguments,
12760 0,
12761 0,
12762 isolate->factory()->undefined_value(),
12763 isolate->factory()->undefined_value(),
12764 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012765}
12766
12767
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012768RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012769 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12770 return message->type();
12771}
12772
12773
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012774RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012775 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12776 return message->arguments();
12777}
12778
12779
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012780RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012781 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12782 return Smi::FromInt(message->start_position());
12783}
12784
12785
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012786RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012787 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12788 return message->script();
12789}
12790
12791
kasper.lund44510672008-07-25 07:37:58 +000012792#ifdef DEBUG
12793// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12794// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012795RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012796 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012797 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012798#define COUNT_ENTRY(Name, argc, ressize) + 1
12799 int entry_count = 0
12800 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12801 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12802 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12803#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012804 Factory* factory = isolate->factory();
12805 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012806 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012807 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012808#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012809 { \
12810 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012811 Handle<String> name; \
12812 /* Inline runtime functions have an underscore in front of the name. */ \
12813 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012814 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012815 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12816 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012817 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012818 Vector<const char>(#Name, StrLength(#Name))); \
12819 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012820 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012821 pair_elements->set(0, *name); \
12822 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012823 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012824 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012825 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012826 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012827 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012828 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012829 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012830 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012831#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012832 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012833 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012834 return *result;
12835}
kasper.lund44510672008-07-25 07:37:58 +000012836#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012837
12838
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012839RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012840 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012841 CONVERT_CHECKED(String, format, args[0]);
12842 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000012843 String::FlatContent format_content = format->GetFlatContent();
12844 RUNTIME_ASSERT(format_content.IsAscii());
12845 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012846 LOGGER->LogRuntime(chars, elms);
12847 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012848}
12849
12850
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012851RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012852 UNREACHABLE(); // implemented as macro in the parser
12853 return NULL;
12854}
12855
12856
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012857#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
12858 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
12859 CONVERT_CHECKED(JSObject, obj, args[0]); \
12860 return isolate->heap()->ToBoolean(obj->Has##Name()); \
12861 }
12862
12863ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
12864ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
12865ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
12866ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
12867ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
12868ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
12869ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
12870ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
12871ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
12872ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
12873ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
12874ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
12875ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
12876
12877#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
12878
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012879// ----------------------------------------------------------------------------
12880// Implementation of Runtime
12881
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012882#define F(name, number_of_args, result_size) \
12883 { Runtime::k##name, Runtime::RUNTIME, #name, \
12884 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012885
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012886
12887#define I(name, number_of_args, result_size) \
12888 { Runtime::kInline##name, Runtime::INLINE, \
12889 "_" #name, NULL, number_of_args, result_size },
12890
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012891static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012892 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012893 INLINE_FUNCTION_LIST(I)
12894 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012895};
12896
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012897
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012898MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12899 Object* dictionary) {
12900 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012901 ASSERT(dictionary != NULL);
12902 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12903 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012904 Object* name_symbol;
12905 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012906 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012907 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12908 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012909 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012910 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12911 String::cast(name_symbol),
12912 Smi::FromInt(i),
12913 PropertyDetails(NONE, NORMAL));
12914 if (!maybe_dictionary->ToObject(&dictionary)) {
12915 // Non-recoverable failure. Calling code must restart heap
12916 // initialization.
12917 return maybe_dictionary;
12918 }
12919 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012920 }
12921 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012922}
12923
12924
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012925const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12926 Heap* heap = name->GetHeap();
12927 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012928 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012929 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012930 int function_index = Smi::cast(smi_index)->value();
12931 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012932 }
12933 return NULL;
12934}
12935
12936
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012937const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012938 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12939}
12940
12941
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012942void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012943 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012944 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012945 if (failure->IsRetryAfterGC()) {
12946 // Try to do a garbage collection; ignore it if it fails. The C
12947 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012948 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012949 } else {
12950 // Handle last resort GC and make sure to allow future allocations
12951 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012952 isolate->counters()->gc_last_resort_from_js()->Increment();
12953 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012954 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012955}
12956
12957
12958} } // namespace v8::internal