blob: df225b63f3fcc66734c27563908ee261584cd2ad [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];
618 return obj->IsJSProxy()
619 ? isolate->heap()->true_value() : isolate->heap()->false_value();
620}
621
622
623RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
624 ASSERT(args.length() == 1);
625 CONVERT_CHECKED(JSProxy, proxy, args[0]);
626 return proxy->handler();
627}
628
629
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000630RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
631 ASSERT(args.length() == 1);
632 CONVERT_CHECKED(JSProxy, proxy, args[0]);
633 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000634 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000635}
636
637
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000638RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000639 NoHandleAllocation ha;
640 ASSERT(args.length() == 1);
641 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000642 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000643 return JSObject::cast(obj)->class_name();
644}
645
ager@chromium.org7c537e22008-10-16 08:43:32 +0000646
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000647RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
648 NoHandleAllocation ha;
649 ASSERT(args.length() == 1);
650 Object* obj = args[0];
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000651 do {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000652 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000653 } while (obj->IsJSObject() &&
654 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000655 return obj;
656}
657
658
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000659RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000660 NoHandleAllocation ha;
661 ASSERT(args.length() == 2);
662 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
663 Object* O = args[0];
664 Object* V = args[1];
665 while (true) {
666 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000667 if (prototype->IsNull()) return isolate->heap()->false_value();
668 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000669 V = prototype;
670 }
671}
672
673
ager@chromium.org9085a012009-05-11 19:22:57 +0000674// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000675RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000676 NoHandleAllocation ha;
677 ASSERT(args.length() == 2);
678 CONVERT_CHECKED(JSObject, jsobject, args[0]);
679 CONVERT_CHECKED(JSObject, proto, args[1]);
680
681 // Sanity checks. The old prototype (that we are replacing) could
682 // theoretically be null, but if it is not null then check that we
683 // didn't already install a hidden prototype here.
684 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
685 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
686 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
687
688 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000689 Object* map_or_failure;
690 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
691 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
692 return maybe_map_or_failure;
693 }
694 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000695 Map* new_proto_map = Map::cast(map_or_failure);
696
lrn@chromium.org303ada72010-10-27 09:33:13 +0000697 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
698 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
699 return maybe_map_or_failure;
700 }
701 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000702 Map* new_map = Map::cast(map_or_failure);
703
704 // Set proto's prototype to be the old prototype of the object.
705 new_proto_map->set_prototype(jsobject->GetPrototype());
706 proto->set_map(new_proto_map);
707 new_proto_map->set_is_hidden_prototype();
708
709 // Set the object's prototype to proto.
710 new_map->set_prototype(proto);
711 jsobject->set_map(new_map);
712
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000713 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000714}
715
716
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000717RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000718 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000719 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000720 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000721 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000722}
723
724
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000725// Recursively traverses hidden prototypes if property is not found
726static void GetOwnPropertyImplementation(JSObject* obj,
727 String* name,
728 LookupResult* result) {
729 obj->LocalLookupRealNamedProperty(name, result);
730
731 if (!result->IsProperty()) {
732 Object* proto = obj->GetPrototype();
733 if (proto->IsJSObject() &&
734 JSObject::cast(proto)->map()->is_hidden_prototype())
735 GetOwnPropertyImplementation(JSObject::cast(proto),
736 name, result);
737 }
738}
739
740
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000741static bool CheckAccessException(LookupResult* result,
742 v8::AccessType access_type) {
743 if (result->type() == CALLBACKS) {
744 Object* callback = result->GetCallbackObject();
745 if (callback->IsAccessorInfo()) {
746 AccessorInfo* info = AccessorInfo::cast(callback);
747 bool can_access =
748 (access_type == v8::ACCESS_HAS &&
749 (info->all_can_read() || info->all_can_write())) ||
750 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
751 (access_type == v8::ACCESS_SET && info->all_can_write());
752 return can_access;
753 }
754 }
755
756 return false;
757}
758
759
760static bool CheckAccess(JSObject* obj,
761 String* name,
762 LookupResult* result,
763 v8::AccessType access_type) {
764 ASSERT(result->IsProperty());
765
766 JSObject* holder = result->holder();
767 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000768 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000769 while (true) {
770 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000771 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000772 // Access check callback denied the access, but some properties
773 // can have a special permissions which override callbacks descision
774 // (currently see v8::AccessControl).
775 break;
776 }
777
778 if (current == holder) {
779 return true;
780 }
781
782 current = JSObject::cast(current->GetPrototype());
783 }
784
785 // API callbacks can have per callback access exceptions.
786 switch (result->type()) {
787 case CALLBACKS: {
788 if (CheckAccessException(result, access_type)) {
789 return true;
790 }
791 break;
792 }
793 case INTERCEPTOR: {
794 // If the object has an interceptor, try real named properties.
795 // Overwrite the result to fetch the correct property later.
796 holder->LookupRealNamedProperty(name, result);
797 if (result->IsProperty()) {
798 if (CheckAccessException(result, access_type)) {
799 return true;
800 }
801 }
802 break;
803 }
804 default:
805 break;
806 }
807
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000808 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000809 return false;
810}
811
812
813// TODO(1095): we should traverse hidden prototype hierachy as well.
814static bool CheckElementAccess(JSObject* obj,
815 uint32_t index,
816 v8::AccessType access_type) {
817 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000818 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000819 return false;
820 }
821
822 return true;
823}
824
825
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000826// Enumerator used as indices into the array returned from GetOwnProperty
827enum PropertyDescriptorIndices {
828 IS_ACCESSOR_INDEX,
829 VALUE_INDEX,
830 GETTER_INDEX,
831 SETTER_INDEX,
832 WRITABLE_INDEX,
833 ENUMERABLE_INDEX,
834 CONFIGURABLE_INDEX,
835 DESCRIPTOR_SIZE
836};
837
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000838// Returns an array with the property description:
839// if args[1] is not a property on args[0]
840// returns undefined
841// if args[1] is a data property on args[0]
842// [false, value, Writeable, Enumerable, Configurable]
843// if args[1] is an accessor on args[0]
844// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000845RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000846 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000847 Heap* heap = isolate->heap();
848 HandleScope scope(isolate);
849 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
850 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000851 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000852 CONVERT_ARG_CHECKED(JSObject, obj, 0);
853 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000854
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000855 // This could be an element.
856 uint32_t index;
857 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000858 switch (obj->HasLocalElement(index)) {
859 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000860 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000861
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000862 case JSObject::STRING_CHARACTER_ELEMENT: {
863 // Special handling of string objects according to ECMAScript 5
864 // 15.5.5.2. Note that this might be a string object with elements
865 // other than the actual string value. This is covered by the
866 // subsequent cases.
867 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
868 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000869 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000870
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000871 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000872 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000873 elms->set(WRITABLE_INDEX, heap->false_value());
874 elms->set(ENUMERABLE_INDEX, heap->false_value());
875 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000876 return *desc;
877 }
878
879 case JSObject::INTERCEPTED_ELEMENT:
880 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000881 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000882 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000883 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000884 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000885 elms->set(WRITABLE_INDEX, heap->true_value());
886 elms->set(ENUMERABLE_INDEX, heap->true_value());
887 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000888 return *desc;
889 }
890
891 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000892 Handle<JSObject> holder = obj;
893 if (obj->IsJSGlobalProxy()) {
894 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000895 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000896 ASSERT(proto->IsJSGlobalObject());
897 holder = Handle<JSObject>(JSObject::cast(proto));
898 }
whesse@chromium.org7b260152011-06-20 15:33:18 +0000899 FixedArray* elements = FixedArray::cast(holder->elements());
900 NumberDictionary* dictionary = NULL;
901 if (elements->map() == heap->non_strict_arguments_elements_map()) {
902 dictionary = NumberDictionary::cast(elements->get(1));
903 } else {
904 dictionary = NumberDictionary::cast(elements);
905 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000906 int entry = dictionary->FindEntry(index);
907 ASSERT(entry != NumberDictionary::kNotFound);
908 PropertyDetails details = dictionary->DetailsAt(entry);
909 switch (details.type()) {
910 case CALLBACKS: {
911 // This is an accessor property with getter and/or setter.
912 FixedArray* callbacks =
913 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000914 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000915 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
916 elms->set(GETTER_INDEX, callbacks->get(0));
917 }
918 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
919 elms->set(SETTER_INDEX, callbacks->get(1));
920 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000921 break;
922 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000923 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000924 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000925 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000926 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000927 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000928 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000929 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000930 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000931 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000932 default:
933 UNREACHABLE();
934 break;
935 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000936 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
937 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000938 return *desc;
939 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000940 }
941 }
942
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000943 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000944 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000945
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000946 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000947 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000948 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000949
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000950 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000951 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000952 }
953
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000954 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
955 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000956
957 bool is_js_accessor = (result.type() == CALLBACKS) &&
958 (result.GetCallbackObject()->IsFixedArray());
959
960 if (is_js_accessor) {
961 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000962 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000963
964 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
965 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
966 elms->set(GETTER_INDEX, structure->get(0));
967 }
968 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
969 elms->set(SETTER_INDEX, structure->get(1));
970 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000971 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000972 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
973 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000974
975 PropertyAttributes attrs;
976 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000977 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000978 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
979 if (!maybe_value->ToObject(&value)) return maybe_value;
980 }
981 elms->set(VALUE_INDEX, value);
982 }
983
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000984 return *desc;
985}
986
987
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000988RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000989 ASSERT(args.length() == 1);
990 CONVERT_CHECKED(JSObject, obj, args[0]);
991 return obj->PreventExtensions();
992}
993
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000995RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000996 ASSERT(args.length() == 1);
997 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000998 if (obj->IsJSGlobalProxy()) {
999 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001000 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001001 ASSERT(proto->IsJSGlobalObject());
1002 obj = JSObject::cast(proto);
1003 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001004 return obj->map()->is_extensible() ? isolate->heap()->true_value()
1005 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001006}
1007
1008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001009RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001010 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001012 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1013 CONVERT_ARG_CHECKED(String, pattern, 1);
1014 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001015 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1016 if (result.is_null()) return Failure::Exception();
1017 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001018}
1019
1020
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001021RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001022 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001023 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001024 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001025 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001026}
1027
1028
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001029RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001030 ASSERT(args.length() == 1);
1031 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001032 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001033 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001034}
1035
1036
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001037RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001038 ASSERT(args.length() == 2);
1039 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001040 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001041 int index = field->value();
1042 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1043 InstanceType type = templ->map()->instance_type();
1044 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1045 type == OBJECT_TEMPLATE_INFO_TYPE);
1046 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001047 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001048 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1049 } else {
1050 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1051 }
1052 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001053}
1054
1055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001056RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001057 ASSERT(args.length() == 1);
1058 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001059 Map* old_map = object->map();
1060 bool needs_access_checks = old_map->is_access_check_needed();
1061 if (needs_access_checks) {
1062 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001063 Object* new_map;
1064 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1065 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1066 }
ager@chromium.org32912102009-01-16 10:38:43 +00001067
1068 Map::cast(new_map)->set_is_access_check_needed(false);
1069 object->set_map(Map::cast(new_map));
1070 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001071 return needs_access_checks ? isolate->heap()->true_value()
1072 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001073}
1074
1075
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001076RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001077 ASSERT(args.length() == 1);
1078 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001079 Map* old_map = object->map();
1080 if (!old_map->is_access_check_needed()) {
1081 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001082 Object* new_map;
1083 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1084 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1085 }
ager@chromium.org32912102009-01-16 10:38:43 +00001086
1087 Map::cast(new_map)->set_is_access_check_needed(true);
1088 object->set_map(Map::cast(new_map));
1089 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001090 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001091}
1092
1093
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001094static Failure* ThrowRedeclarationError(Isolate* isolate,
1095 const char* type,
1096 Handle<String> name) {
1097 HandleScope scope(isolate);
1098 Handle<Object> type_handle =
1099 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001100 Handle<Object> args[2] = { type_handle, name };
1101 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001102 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1103 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001104}
1105
1106
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001107RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001108 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001109 HandleScope scope(isolate);
1110 Handle<GlobalObject> global = Handle<GlobalObject>(
1111 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001112
ager@chromium.org3811b432009-10-28 14:53:37 +00001113 Handle<Context> context = args.at<Context>(0);
1114 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001115 bool is_eval = args.smi_at(2) == 1;
1116 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001117 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001118
1119 // Compute the property attributes. According to ECMA-262, section
1120 // 13, page 71, the property must be read-only and
1121 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1122 // property as read-only, so we don't either.
1123 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1124
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001125 // Traverse the name/value pairs and set the properties.
1126 int length = pairs->length();
1127 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001128 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001129 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001130 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001131
1132 // We have to declare a global const property. To capture we only
1133 // assign to it when evaluating the assignment for "const x =
1134 // <expr>" the initial value is the hole.
1135 bool is_const_property = value->IsTheHole();
1136
1137 if (value->IsUndefined() || is_const_property) {
1138 // Lookup the property in the global object, and don't set the
1139 // value of the variable if the property is already there.
1140 LookupResult lookup;
1141 global->Lookup(*name, &lookup);
1142 if (lookup.IsProperty()) {
1143 // Determine if the property is local by comparing the holder
1144 // against the global object. The information will be used to
1145 // avoid throwing re-declaration errors when declaring
1146 // variables or constants that exist in the prototype chain.
1147 bool is_local = (*global == lookup.holder());
1148 // Get the property attributes and determine if the property is
1149 // read-only.
1150 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1151 bool is_read_only = (attributes & READ_ONLY) != 0;
1152 if (lookup.type() == INTERCEPTOR) {
1153 // If the interceptor says the property is there, we
1154 // just return undefined without overwriting the property.
1155 // Otherwise, we continue to setting the property.
1156 if (attributes != ABSENT) {
1157 // Check if the existing property conflicts with regards to const.
1158 if (is_local && (is_read_only || is_const_property)) {
1159 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001160 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001161 };
1162 // The property already exists without conflicting: Go to
1163 // the next declaration.
1164 continue;
1165 }
1166 // Fall-through and introduce the absent property by using
1167 // SetProperty.
1168 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001169 // For const properties, we treat a callback with this name
1170 // even in the prototype as a conflicting declaration.
1171 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001172 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001173 }
1174 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001175 if (is_local && (is_read_only || is_const_property)) {
1176 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001177 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001178 }
1179 // The property already exists without conflicting: Go to
1180 // the next declaration.
1181 continue;
1182 }
1183 }
1184 } else {
1185 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001186 Handle<SharedFunctionInfo> shared =
1187 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001188 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001189 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1190 context,
1191 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001192 value = function;
1193 }
1194
1195 LookupResult lookup;
1196 global->LocalLookup(*name, &lookup);
1197
1198 PropertyAttributes attributes = is_const_property
1199 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1200 : base;
1201
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001202 // There's a local property that we need to overwrite because
1203 // we're either declaring a function or there's an interceptor
1204 // that claims the property is absent.
1205 //
1206 // Check for conflicting re-declarations. We cannot have
1207 // conflicting types in case of intercepted properties because
1208 // they are absent.
1209 if (lookup.IsProperty() &&
1210 (lookup.type() != INTERCEPTOR) &&
1211 (lookup.IsReadOnly() || is_const_property)) {
1212 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001213 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001214 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001216 // Safari does not allow the invocation of callback setters for
1217 // function declarations. To mimic this behavior, we do not allow
1218 // the invocation of setters for function values. This makes a
1219 // difference for global functions with the same names as event
1220 // handlers such as "function onload() {}". Firefox does call the
1221 // onload setter in those case and Safari does not. We follow
1222 // Safari for compatibility.
1223 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001224 // Do not change DONT_DELETE to false from true.
1225 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1226 attributes = static_cast<PropertyAttributes>(
1227 attributes | (lookup.GetAttributes() & DONT_DELETE));
1228 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001229 RETURN_IF_EMPTY_HANDLE(isolate,
1230 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001231 name,
1232 value,
1233 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001234 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001235 RETURN_IF_EMPTY_HANDLE(isolate,
1236 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001237 name,
1238 value,
1239 attributes,
1240 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001241 }
1242 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001243
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001244 ASSERT(!isolate->has_pending_exception());
1245 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001246}
1247
1248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001249RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001250 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001251 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001252
ager@chromium.org7c537e22008-10-16 08:43:32 +00001253 CONVERT_ARG_CHECKED(Context, context, 0);
1254 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001255 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001256 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001257 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001258
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001259 // Declarations are always done in a function or global context.
1260 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001261
1262 int index;
1263 PropertyAttributes attributes;
1264 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001265 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266 context->Lookup(name, flags, &index, &attributes);
1267
1268 if (attributes != ABSENT) {
1269 // The name was declared before; check for conflicting
1270 // re-declarations: This is similar to the code in parser.cc in
1271 // the AstBuildingParser::Declare function.
1272 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1273 // Functions are not read-only.
1274 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1275 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001276 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277 }
1278
1279 // Initialize it if necessary.
1280 if (*initial_value != NULL) {
1281 if (index >= 0) {
1282 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001283 // the function context or the arguments object.
1284 if (holder->IsContext()) {
1285 ASSERT(holder.is_identical_to(context));
1286 if (((attributes & READ_ONLY) == 0) ||
1287 context->get(index)->IsTheHole()) {
1288 context->set(index, *initial_value);
1289 }
1290 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001291 // The holder is an arguments object.
1292 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001293 Handle<Object> result = SetElement(arguments, index, initial_value,
1294 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001295 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001296 }
1297 } else {
1298 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001299 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001300 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001301 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001302 SetProperty(context_ext, name, initial_value,
1303 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001304 }
1305 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001306
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001307 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001308 // The property is not in the function context. It needs to be
1309 // "declared" in the function context's extension context, or in the
1310 // global context.
1311 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001312 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001313 // The function context's extension context exists - use it.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001314 context_ext = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001315 } else {
1316 // The function context's extension context does not exists - allocate
1317 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001318 context_ext = isolate->factory()->NewJSObject(
1319 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001320 // And store it in the extension slot.
1321 context->set_extension(*context_ext);
1322 }
1323 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001324
ager@chromium.org7c537e22008-10-16 08:43:32 +00001325 // Declare the property by setting it to the initial value if provided,
1326 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1327 // constant declarations).
1328 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001329 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001330 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001331 // Declaring a const context slot is a conflicting declaration if
1332 // there is a callback with that name in a prototype. It is
1333 // allowed to introduce const variables in
1334 // JSContextExtensionObjects. They are treated specially in
1335 // SetProperty and no setters are invoked for those since they are
1336 // not real JSObjects.
1337 if (initial_value->IsTheHole() &&
1338 !context_ext->IsJSContextExtensionObject()) {
1339 LookupResult lookup;
1340 context_ext->Lookup(*name, &lookup);
1341 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001342 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001343 }
1344 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001345 RETURN_IF_EMPTY_HANDLE(isolate,
1346 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001347 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001348 }
1349
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001350 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001351}
1352
1353
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001354RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001355 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001356 // args[0] == name
1357 // args[1] == strict_mode
1358 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001359
1360 // Determine if we need to assign to the variable if it already
1361 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001362 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1363 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001364
1365 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001366 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001367 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001368 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001369 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001370
1371 // According to ECMA-262, section 12.2, page 62, the property must
1372 // not be deletable.
1373 PropertyAttributes attributes = DONT_DELETE;
1374
1375 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001376 // there, there is a property with this name in the prototype chain.
1377 // We follow Safari and Firefox behavior and only set the property
1378 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001379 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001380 // Note that objects can have hidden prototypes, so we need to traverse
1381 // the whole chain of hidden prototypes to do a 'local' lookup.
1382 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001383 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001384 while (true) {
1385 real_holder->LocalLookup(*name, &lookup);
1386 if (lookup.IsProperty()) {
1387 // Determine if this is a redeclaration of something read-only.
1388 if (lookup.IsReadOnly()) {
1389 // If we found readonly property on one of hidden prototypes,
1390 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001391 if (real_holder != isolate->context()->global()) break;
1392 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001393 }
1394
1395 // Determine if this is a redeclaration of an intercepted read-only
1396 // property and figure out if the property exists at all.
1397 bool found = true;
1398 PropertyType type = lookup.type();
1399 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001400 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001401 Handle<JSObject> holder(real_holder);
1402 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1403 real_holder = *holder;
1404 if (intercepted == ABSENT) {
1405 // The interceptor claims the property isn't there. We need to
1406 // make sure to introduce it.
1407 found = false;
1408 } else if ((intercepted & READ_ONLY) != 0) {
1409 // The property is present, but read-only. Since we're trying to
1410 // overwrite it with a variable declaration we must throw a
1411 // re-declaration error. However if we found readonly property
1412 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001413 if (real_holder != isolate->context()->global()) break;
1414 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001415 }
1416 }
1417
1418 if (found && !assign) {
1419 // The global property is there and we're not assigning any value
1420 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001421 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001422 }
1423
1424 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001425 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001426 return real_holder->SetProperty(
1427 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001428 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001429
1430 Object* proto = real_holder->GetPrototype();
1431 if (!proto->IsJSObject())
1432 break;
1433
1434 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1435 break;
1436
1437 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001438 }
1439
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001440 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001441 if (assign) {
1442 return global->SetProperty(*name, args[2], attributes, strict_mode);
1443 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001444 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001445}
1446
1447
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001448RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001449 // All constants are declared with an initial value. The name
1450 // of the constant is the first argument and the initial value
1451 // is the second.
1452 RUNTIME_ASSERT(args.length() == 2);
1453 CONVERT_ARG_CHECKED(String, name, 0);
1454 Handle<Object> value = args.at<Object>(1);
1455
1456 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001457 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001458
1459 // According to ECMA-262, section 12.2, page 62, the property must
1460 // not be deletable. Since it's a const, it must be READ_ONLY too.
1461 PropertyAttributes attributes =
1462 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1463
1464 // Lookup the property locally in the global object. If it isn't
1465 // there, we add the property and take special precautions to always
1466 // add it as a local property even in case of callbacks in the
1467 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001468 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001469 LookupResult lookup;
1470 global->LocalLookup(*name, &lookup);
1471 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001472 return global->SetLocalPropertyIgnoreAttributes(*name,
1473 *value,
1474 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001475 }
1476
1477 // Determine if this is a redeclaration of something not
1478 // read-only. In case the result is hidden behind an interceptor we
1479 // need to ask it for the property attributes.
1480 if (!lookup.IsReadOnly()) {
1481 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001482 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001483 }
1484
1485 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1486
1487 // Throw re-declaration error if the intercepted property is present
1488 // but not read-only.
1489 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001490 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001491 }
1492
1493 // Restore global object from context (in case of GC) and continue
1494 // with setting the value because the property is either absent or
1495 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001496 HandleScope handle_scope(isolate);
1497 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001498
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001499 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001500 // property through an interceptor and only do it if it's
1501 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001502 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001503 RETURN_IF_EMPTY_HANDLE(isolate,
1504 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001505 name,
1506 value,
1507 attributes,
1508 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001509 return *value;
1510 }
1511
1512 // Set the value, but only we're assigning the initial value to a
1513 // constant. For now, we determine this by checking if the
1514 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001515 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001516 PropertyType type = lookup.type();
1517 if (type == FIELD) {
1518 FixedArray* properties = global->properties();
1519 int index = lookup.GetFieldIndex();
1520 if (properties->get(index)->IsTheHole()) {
1521 properties->set(index, *value);
1522 }
1523 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001524 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1525 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001526 }
1527 } else {
1528 // Ignore re-initialization of constants that have already been
1529 // assigned a function value.
1530 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1531 }
1532
1533 // Use the set value as the result of the operation.
1534 return *value;
1535}
1536
1537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001538RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001539 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001540 ASSERT(args.length() == 3);
1541
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001542 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 ASSERT(!value->IsTheHole());
1544 CONVERT_ARG_CHECKED(Context, context, 1);
1545 Handle<String> name(String::cast(args[2]));
1546
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001547 // Initializations are always done in a function or global context.
1548 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001549
1550 int index;
1551 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001552 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001553 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001554 context->Lookup(name, flags, &index, &attributes);
1555
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001556 // In most situations, the property introduced by the const
1557 // declaration should be present in the context extension object.
1558 // However, because declaration and initialization are separate, the
1559 // property might have been deleted (if it was introduced by eval)
1560 // before we reach the initialization point.
1561 //
1562 // Example:
1563 //
1564 // function f() { eval("delete x; const x;"); }
1565 //
1566 // In that case, the initialization behaves like a normal assignment
1567 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001568 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001569 if (holder->IsContext()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001570 // Property was found in a context. Perform the assignment if we
1571 // found some non-constant or an uninitialized constant.
1572 Handle<Context> context = Handle<Context>::cast(holder);
1573 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1574 context->set(index, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001575 }
1576 } else {
1577 // The holder is an arguments object.
1578 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001579 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001580 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001581 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001582 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001583 }
1584 return *value;
1585 }
1586
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001587 // The property could not be found, we introduce it in the global
1588 // context.
1589 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001590 Handle<JSObject> global = Handle<JSObject>(
1591 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001592 // Strict mode not needed (const disallowed in strict mode).
1593 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001594 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001595 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001596 return *value;
1597 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001598
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001599 // The property was present in a context extension object.
1600 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001601
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001602 if (*context_ext == context->extension()) {
1603 // This is the property that was introduced by the const
1604 // declaration. Set it if it hasn't been set before. NOTE: We
1605 // cannot use GetProperty() to get the current value as it
1606 // 'unholes' the value.
1607 LookupResult lookup;
1608 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1609 ASSERT(lookup.IsProperty()); // the property was declared
1610 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1611
1612 PropertyType type = lookup.type();
1613 if (type == FIELD) {
1614 FixedArray* properties = context_ext->properties();
1615 int index = lookup.GetFieldIndex();
1616 if (properties->get(index)->IsTheHole()) {
1617 properties->set(index, *value);
1618 }
1619 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001620 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1621 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001622 }
1623 } else {
1624 // We should not reach here. Any real, named property should be
1625 // either a field or a dictionary slot.
1626 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001627 }
1628 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001629 // The property was found in a different context extension object.
1630 // Set it if it is not a read-only property.
1631 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001632 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001633 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001634 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001635 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001636 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001637 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001638
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001639 return *value;
1640}
1641
1642
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001643RUNTIME_FUNCTION(MaybeObject*,
1644 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001645 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001646 ASSERT(args.length() == 2);
1647 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001648 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001649 if (object->HasFastProperties()) {
1650 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1651 }
1652 return *object;
1653}
1654
1655
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001656RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001657 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001658 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001659 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1660 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001661 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001662 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001663 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001664 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001665 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001666 RUNTIME_ASSERT(index >= 0);
1667 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001668 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001669 Handle<Object> result = RegExpImpl::Exec(regexp,
1670 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001671 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001672 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001673 if (result.is_null()) return Failure::Exception();
1674 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001675}
1676
1677
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001678RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001679 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001680 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001681 if (elements_count < 0 ||
1682 elements_count > FixedArray::kMaxLength ||
1683 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001684 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001685 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001686 Object* new_object;
1687 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001688 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001689 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1690 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001691 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001692 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1693 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001694 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1695 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001696 {
1697 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001698 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001699 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001700 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001701 }
1702 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001703 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001704 array->set_elements(elements);
1705 array->set_length(Smi::FromInt(elements_count));
1706 // Write in-object properties after the length of the array.
1707 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1708 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1709 return array;
1710}
1711
1712
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001713RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001714 AssertNoAllocation no_alloc;
1715 ASSERT(args.length() == 5);
1716 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1717 CONVERT_CHECKED(String, source, args[1]);
1718
1719 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001720 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001721
1722 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001723 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001724
1725 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001726 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001727
1728 Map* map = regexp->map();
1729 Object* constructor = map->constructor();
1730 if (constructor->IsJSFunction() &&
1731 JSFunction::cast(constructor)->initial_map() == map) {
1732 // If we still have the original map, set in-object properties directly.
1733 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1734 // TODO(lrn): Consider skipping write barrier on booleans as well.
1735 // Both true and false should be in oldspace at all times.
1736 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1737 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1738 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1739 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1740 Smi::FromInt(0),
1741 SKIP_WRITE_BARRIER);
1742 return regexp;
1743 }
1744
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001745 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001746 PropertyAttributes final =
1747 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1748 PropertyAttributes writable =
1749 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001750 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001751 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001752 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001753 source,
1754 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001755 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001756 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001757 global,
1758 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001759 ASSERT(!result->IsFailure());
1760 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001761 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001762 ignoreCase,
1763 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001764 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001765 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001766 multiline,
1767 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001768 ASSERT(!result->IsFailure());
1769 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001770 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001771 Smi::FromInt(0),
1772 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001773 ASSERT(!result->IsFailure());
1774 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001775 return regexp;
1776}
1777
1778
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001779RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001780 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001781 ASSERT(args.length() == 1);
1782 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1783 // This is necessary to enable fast checks for absence of elements
1784 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001785 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001786 return Smi::FromInt(0);
1787}
1788
1789
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001790static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1791 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001792 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001793 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001794 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1795 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1796 Handle<JSFunction> optimized =
1797 isolate->factory()->NewFunction(key,
1798 JS_OBJECT_TYPE,
1799 JSObject::kHeaderSize,
1800 code,
1801 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001802 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001803 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001804 return optimized;
1805}
1806
1807
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001808RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001809 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001810 ASSERT(args.length() == 1);
1811 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1812
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001813 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1814 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1815 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1816 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1817 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1818 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1819 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001820
1821 return *holder;
1822}
1823
1824
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001825RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001826 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001827 Context* global_context =
1828 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001829 return global_context->global()->global_receiver();
1830}
1831
1832
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001833RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001834 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001835 ASSERT(args.length() == 4);
1836 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001837 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001838 Handle<String> pattern = args.at<String>(2);
1839 Handle<String> flags = args.at<String>(3);
1840
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001841 // Get the RegExp function from the context in the literals array.
1842 // This is the RegExp function from the context in which the
1843 // function was created. We do not use the RegExp function from the
1844 // current global context because this might be the RegExp function
1845 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001846 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001847 Handle<JSFunction>(
1848 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001849 // Compute the regular expression literal.
1850 bool has_pending_exception;
1851 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001852 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1853 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001854 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001855 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001856 return Failure::Exception();
1857 }
1858 literals->set(index, *regexp);
1859 return *regexp;
1860}
1861
1862
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001863RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001864 NoHandleAllocation ha;
1865 ASSERT(args.length() == 1);
1866
1867 CONVERT_CHECKED(JSFunction, f, args[0]);
1868 return f->shared()->name();
1869}
1870
1871
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001872RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001873 NoHandleAllocation ha;
1874 ASSERT(args.length() == 2);
1875
1876 CONVERT_CHECKED(JSFunction, f, args[0]);
1877 CONVERT_CHECKED(String, name, args[1]);
1878 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001879 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001880}
1881
1882
whesse@chromium.org7b260152011-06-20 15:33:18 +00001883RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1884 HandleScope scope(isolate);
1885 ASSERT(args.length() == 1);
1886
1887 CONVERT_CHECKED(JSFunction, fun, args[0]);
1888 fun->shared()->set_bound(true);
1889 return isolate->heap()->undefined_value();
1890}
1891
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001892RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001893 NoHandleAllocation ha;
1894 ASSERT(args.length() == 1);
1895
1896 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001897 Object* obj = f->RemovePrototype();
1898 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001899
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001900 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001901}
1902
1903
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001904RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001905 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001906 ASSERT(args.length() == 1);
1907
1908 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001909 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1910 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001911
1912 return *GetScriptWrapper(Handle<Script>::cast(script));
1913}
1914
1915
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001916RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
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()->GetSourceCode();
1922}
1923
1924
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001925RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001926 NoHandleAllocation ha;
1927 ASSERT(args.length() == 1);
1928
1929 CONVERT_CHECKED(JSFunction, fun, args[0]);
1930 int pos = fun->shared()->start_position();
1931 return Smi::FromInt(pos);
1932}
1933
1934
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001935RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001936 ASSERT(args.length() == 2);
1937
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001938 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001939 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1940
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001941 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1942
1943 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001944 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001945}
1946
1947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001948RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001949 NoHandleAllocation ha;
1950 ASSERT(args.length() == 2);
1951
1952 CONVERT_CHECKED(JSFunction, fun, args[0]);
1953 CONVERT_CHECKED(String, name, args[1]);
1954 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001955 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001956}
1957
1958
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001959RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001960 NoHandleAllocation ha;
1961 ASSERT(args.length() == 2);
1962
1963 CONVERT_CHECKED(JSFunction, fun, args[0]);
1964 CONVERT_CHECKED(Smi, length, args[1]);
1965 fun->shared()->set_length(length->value());
1966 return length;
1967}
1968
1969
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001970RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001971 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001972 ASSERT(args.length() == 2);
1973
1974 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001975 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001976 Object* obj;
1977 { MaybeObject* maybe_obj =
1978 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1979 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1980 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001981 return args[0]; // return TOS
1982}
1983
1984
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001985RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
1986 NoHandleAllocation ha;
1987 RUNTIME_ASSERT(args.length() == 1);
1988 CONVERT_CHECKED(JSFunction, function, args[0]);
1989
1990 MaybeObject* maybe_name =
1991 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
1992 String* name;
1993 if (!maybe_name->To(&name)) return maybe_name;
1994
1995 if (function->HasFastProperties()) {
1996 // Construct a new field descriptor with updated attributes.
1997 DescriptorArray* instance_desc = function->map()->instance_descriptors();
1998 int index = instance_desc->Search(name);
1999 ASSERT(index != DescriptorArray::kNotFound);
2000 PropertyDetails details(instance_desc->GetDetails(index));
2001 CallbacksDescriptor new_desc(name,
2002 instance_desc->GetValue(index),
2003 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2004 details.index());
2005 // Construct a new field descriptors array containing the new descriptor.
2006 Object* descriptors_unchecked;
2007 { MaybeObject* maybe_descriptors_unchecked =
2008 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2009 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2010 return maybe_descriptors_unchecked;
2011 }
2012 }
2013 DescriptorArray* new_descriptors =
2014 DescriptorArray::cast(descriptors_unchecked);
2015 // Create a new map featuring the new field descriptors array.
2016 Object* map_unchecked;
2017 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2018 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2019 return maybe_map_unchecked;
2020 }
2021 }
2022 Map* new_map = Map::cast(map_unchecked);
2023 new_map->set_instance_descriptors(new_descriptors);
2024 function->set_map(new_map);
2025 } else { // Dictionary properties.
2026 // Directly manipulate the property details.
2027 int entry = function->property_dictionary()->FindEntry(name);
2028 ASSERT(entry != StringDictionary::kNotFound);
2029 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2030 PropertyDetails new_details(
2031 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2032 details.type(),
2033 details.index());
2034 function->property_dictionary()->DetailsAtPut(entry, new_details);
2035 }
2036 return function;
2037}
2038
2039
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002040RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002041 NoHandleAllocation ha;
2042 ASSERT(args.length() == 1);
2043
2044 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002045 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
2046 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002047}
2048
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002049
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002050RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002051 NoHandleAllocation ha;
2052 ASSERT(args.length() == 1);
2053
2054 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002055 return f->IsBuiltin() ? isolate->heap()->true_value() :
2056 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002057}
2058
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002059
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002060RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002061 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002062 ASSERT(args.length() == 2);
2063
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002064 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002065 Handle<Object> code = args.at<Object>(1);
2066
2067 Handle<Context> context(target->context());
2068
2069 if (!code->IsNull()) {
2070 RUNTIME_ASSERT(code->IsJSFunction());
2071 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002072 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002073
2074 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002075 return Failure::Exception();
2076 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002077 // Since we don't store the source for this we should never
2078 // optimize this.
2079 shared->code()->set_optimizable(false);
2080
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002081 // Set the code, scope info, formal parameter count,
2082 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002083 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002084 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002085 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002086 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002087 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002088 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002089 // Set the source code of the target function to undefined.
2090 // SetCode is only used for built-in constructors like String,
2091 // Array, and Object, and some web code
2092 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002093 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002094 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002095 // Clear the optimization hints related to the compiled code as these are no
2096 // longer valid when the code is overwritten.
2097 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002098 context = Handle<Context>(fun->context());
2099
2100 // Make sure we get a fresh copy of the literal vector to avoid
2101 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002102 int number_of_literals = fun->NumberOfLiterals();
2103 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002104 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002105 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002106 // Insert the object, regexp and array functions in the literals
2107 // array prefix. These are the functions that will be used when
2108 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002109 literals->set(JSFunction::kLiteralGlobalContextIndex,
2110 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002111 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002112 // It's okay to skip the write barrier here because the literals
2113 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002114 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002115 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002116 }
2117
2118 target->set_context(*context);
2119 return *target;
2120}
2121
2122
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002123RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002124 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002125 ASSERT(args.length() == 2);
2126 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002127 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002128 RUNTIME_ASSERT(num >= 0);
2129 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002130 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002131}
2132
2133
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002134MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2135 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002136 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002137 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002138 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002139 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002140 }
2141 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002142 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002143}
2144
2145
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002146RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002147 NoHandleAllocation ha;
2148 ASSERT(args.length() == 2);
2149
2150 CONVERT_CHECKED(String, subject, args[0]);
2151 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002152 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002153
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002154 uint32_t i = 0;
2155 if (index->IsSmi()) {
2156 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002157 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002158 i = value;
2159 } else {
2160 ASSERT(index->IsHeapNumber());
2161 double value = HeapNumber::cast(index)->value();
2162 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002163 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002164
2165 // Flatten the string. If someone wants to get a char at an index
2166 // in a cons string, it is likely that more indices will be
2167 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002168 Object* flat;
2169 { MaybeObject* maybe_flat = subject->TryFlatten();
2170 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2171 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002172 subject = String::cast(flat);
2173
2174 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002175 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002176 }
2177
2178 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002179}
2180
2181
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002182RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002183 NoHandleAllocation ha;
2184 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002185 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002186}
2187
lrn@chromium.org25156de2010-04-06 13:10:27 +00002188
2189class FixedArrayBuilder {
2190 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002191 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2192 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002193 length_(0) {
2194 // Require a non-zero initial size. Ensures that doubling the size to
2195 // extend the array will work.
2196 ASSERT(initial_capacity > 0);
2197 }
2198
2199 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2200 : array_(backing_store),
2201 length_(0) {
2202 // Require a non-zero initial size. Ensures that doubling the size to
2203 // extend the array will work.
2204 ASSERT(backing_store->length() > 0);
2205 }
2206
2207 bool HasCapacity(int elements) {
2208 int length = array_->length();
2209 int required_length = length_ + elements;
2210 return (length >= required_length);
2211 }
2212
2213 void EnsureCapacity(int elements) {
2214 int length = array_->length();
2215 int required_length = length_ + elements;
2216 if (length < required_length) {
2217 int new_length = length;
2218 do {
2219 new_length *= 2;
2220 } while (new_length < required_length);
2221 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002222 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002223 array_->CopyTo(0, *extended_array, 0, length_);
2224 array_ = extended_array;
2225 }
2226 }
2227
2228 void Add(Object* value) {
2229 ASSERT(length_ < capacity());
2230 array_->set(length_, value);
2231 length_++;
2232 }
2233
2234 void Add(Smi* value) {
2235 ASSERT(length_ < capacity());
2236 array_->set(length_, value);
2237 length_++;
2238 }
2239
2240 Handle<FixedArray> array() {
2241 return array_;
2242 }
2243
2244 int length() {
2245 return length_;
2246 }
2247
2248 int capacity() {
2249 return array_->length();
2250 }
2251
2252 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002253 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002254 result_array->set_length(Smi::FromInt(length_));
2255 return result_array;
2256 }
2257
2258 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2259 target_array->set_elements(*array_);
2260 target_array->set_length(Smi::FromInt(length_));
2261 return target_array;
2262 }
2263
2264 private:
2265 Handle<FixedArray> array_;
2266 int length_;
2267};
2268
2269
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002270// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002271const int kStringBuilderConcatHelperLengthBits = 11;
2272const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002273
2274template <typename schar>
2275static inline void StringBuilderConcatHelper(String*,
2276 schar*,
2277 FixedArray*,
2278 int);
2279
lrn@chromium.org25156de2010-04-06 13:10:27 +00002280typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2281 StringBuilderSubstringLength;
2282typedef BitField<int,
2283 kStringBuilderConcatHelperLengthBits,
2284 kStringBuilderConcatHelperPositionBits>
2285 StringBuilderSubstringPosition;
2286
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002287
2288class ReplacementStringBuilder {
2289 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002290 ReplacementStringBuilder(Heap* heap,
2291 Handle<String> subject,
2292 int estimated_part_count)
2293 : heap_(heap),
2294 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002295 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002296 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002297 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002298 // Require a non-zero initial size. Ensures that doubling the size to
2299 // extend the array will work.
2300 ASSERT(estimated_part_count > 0);
2301 }
2302
lrn@chromium.org25156de2010-04-06 13:10:27 +00002303 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2304 int from,
2305 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002306 ASSERT(from >= 0);
2307 int length = to - from;
2308 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002309 if (StringBuilderSubstringLength::is_valid(length) &&
2310 StringBuilderSubstringPosition::is_valid(from)) {
2311 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2312 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002313 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002314 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002315 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002316 builder->Add(Smi::FromInt(-length));
2317 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002318 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002319 }
2320
2321
2322 void EnsureCapacity(int elements) {
2323 array_builder_.EnsureCapacity(elements);
2324 }
2325
2326
2327 void AddSubjectSlice(int from, int to) {
2328 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002329 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002330 }
2331
2332
2333 void AddString(Handle<String> string) {
2334 int length = string->length();
2335 ASSERT(length > 0);
2336 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002337 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002338 is_ascii_ = false;
2339 }
2340 IncrementCharacterCount(length);
2341 }
2342
2343
2344 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002345 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002346 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002347 }
2348
2349 Handle<String> joined_string;
2350 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002351 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002352 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002353 char* char_buffer = seq->GetChars();
2354 StringBuilderConcatHelper(*subject_,
2355 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002356 *array_builder_.array(),
2357 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002358 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002359 } else {
2360 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002361 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002362 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002363 uc16* char_buffer = seq->GetChars();
2364 StringBuilderConcatHelper(*subject_,
2365 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002366 *array_builder_.array(),
2367 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002368 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002369 }
2370 return joined_string;
2371 }
2372
2373
2374 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002375 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002376 V8::FatalProcessOutOfMemory("String.replace result too large.");
2377 }
2378 character_count_ += by;
2379 }
2380
lrn@chromium.org25156de2010-04-06 13:10:27 +00002381 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002382 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002383 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002384
lrn@chromium.org25156de2010-04-06 13:10:27 +00002385 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002386 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2387 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002388 }
2389
2390
ager@chromium.org04921a82011-06-27 13:21:41 +00002391 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2392 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002393 }
2394
2395
2396 void AddElement(Object* element) {
2397 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002398 ASSERT(array_builder_.capacity() > array_builder_.length());
2399 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002400 }
2401
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002402 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002403 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002404 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002405 int character_count_;
2406 bool is_ascii_;
2407};
2408
2409
2410class CompiledReplacement {
2411 public:
2412 CompiledReplacement()
2413 : parts_(1), replacement_substrings_(0) {}
2414
2415 void Compile(Handle<String> replacement,
2416 int capture_count,
2417 int subject_length);
2418
2419 void Apply(ReplacementStringBuilder* builder,
2420 int match_from,
2421 int match_to,
2422 Handle<JSArray> last_match_info);
2423
2424 // Number of distinct parts of the replacement pattern.
2425 int parts() {
2426 return parts_.length();
2427 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002428
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002429 private:
2430 enum PartType {
2431 SUBJECT_PREFIX = 1,
2432 SUBJECT_SUFFIX,
2433 SUBJECT_CAPTURE,
2434 REPLACEMENT_SUBSTRING,
2435 REPLACEMENT_STRING,
2436
2437 NUMBER_OF_PART_TYPES
2438 };
2439
2440 struct ReplacementPart {
2441 static inline ReplacementPart SubjectMatch() {
2442 return ReplacementPart(SUBJECT_CAPTURE, 0);
2443 }
2444 static inline ReplacementPart SubjectCapture(int capture_index) {
2445 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2446 }
2447 static inline ReplacementPart SubjectPrefix() {
2448 return ReplacementPart(SUBJECT_PREFIX, 0);
2449 }
2450 static inline ReplacementPart SubjectSuffix(int subject_length) {
2451 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2452 }
2453 static inline ReplacementPart ReplacementString() {
2454 return ReplacementPart(REPLACEMENT_STRING, 0);
2455 }
2456 static inline ReplacementPart ReplacementSubString(int from, int to) {
2457 ASSERT(from >= 0);
2458 ASSERT(to > from);
2459 return ReplacementPart(-from, to);
2460 }
2461
2462 // If tag <= 0 then it is the negation of a start index of a substring of
2463 // the replacement pattern, otherwise it's a value from PartType.
2464 ReplacementPart(int tag, int data)
2465 : tag(tag), data(data) {
2466 // Must be non-positive or a PartType value.
2467 ASSERT(tag < NUMBER_OF_PART_TYPES);
2468 }
2469 // Either a value of PartType or a non-positive number that is
2470 // the negation of an index into the replacement string.
2471 int tag;
2472 // The data value's interpretation depends on the value of tag:
2473 // tag == SUBJECT_PREFIX ||
2474 // tag == SUBJECT_SUFFIX: data is unused.
2475 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2476 // tag == REPLACEMENT_SUBSTRING ||
2477 // tag == REPLACEMENT_STRING: data is index into array of substrings
2478 // of the replacement string.
2479 // tag <= 0: Temporary representation of the substring of the replacement
2480 // string ranging over -tag .. data.
2481 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2482 // substring objects.
2483 int data;
2484 };
2485
2486 template<typename Char>
2487 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2488 Vector<Char> characters,
2489 int capture_count,
2490 int subject_length) {
2491 int length = characters.length();
2492 int last = 0;
2493 for (int i = 0; i < length; i++) {
2494 Char c = characters[i];
2495 if (c == '$') {
2496 int next_index = i + 1;
2497 if (next_index == length) { // No next character!
2498 break;
2499 }
2500 Char c2 = characters[next_index];
2501 switch (c2) {
2502 case '$':
2503 if (i > last) {
2504 // There is a substring before. Include the first "$".
2505 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2506 last = next_index + 1; // Continue after the second "$".
2507 } else {
2508 // Let the next substring start with the second "$".
2509 last = next_index;
2510 }
2511 i = next_index;
2512 break;
2513 case '`':
2514 if (i > last) {
2515 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2516 }
2517 parts->Add(ReplacementPart::SubjectPrefix());
2518 i = next_index;
2519 last = i + 1;
2520 break;
2521 case '\'':
2522 if (i > last) {
2523 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2524 }
2525 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2526 i = next_index;
2527 last = i + 1;
2528 break;
2529 case '&':
2530 if (i > last) {
2531 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2532 }
2533 parts->Add(ReplacementPart::SubjectMatch());
2534 i = next_index;
2535 last = i + 1;
2536 break;
2537 case '0':
2538 case '1':
2539 case '2':
2540 case '3':
2541 case '4':
2542 case '5':
2543 case '6':
2544 case '7':
2545 case '8':
2546 case '9': {
2547 int capture_ref = c2 - '0';
2548 if (capture_ref > capture_count) {
2549 i = next_index;
2550 continue;
2551 }
2552 int second_digit_index = next_index + 1;
2553 if (second_digit_index < length) {
2554 // Peek ahead to see if we have two digits.
2555 Char c3 = characters[second_digit_index];
2556 if ('0' <= c3 && c3 <= '9') { // Double digits.
2557 int double_digit_ref = capture_ref * 10 + c3 - '0';
2558 if (double_digit_ref <= capture_count) {
2559 next_index = second_digit_index;
2560 capture_ref = double_digit_ref;
2561 }
2562 }
2563 }
2564 if (capture_ref > 0) {
2565 if (i > last) {
2566 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2567 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002568 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002569 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2570 last = next_index + 1;
2571 }
2572 i = next_index;
2573 break;
2574 }
2575 default:
2576 i = next_index;
2577 break;
2578 }
2579 }
2580 }
2581 if (length > last) {
2582 if (last == 0) {
2583 parts->Add(ReplacementPart::ReplacementString());
2584 } else {
2585 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2586 }
2587 }
2588 }
2589
2590 ZoneList<ReplacementPart> parts_;
2591 ZoneList<Handle<String> > replacement_substrings_;
2592};
2593
2594
2595void CompiledReplacement::Compile(Handle<String> replacement,
2596 int capture_count,
2597 int subject_length) {
2598 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002599 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002600 AssertNoAllocation no_alloc;
2601 ParseReplacementPattern(&parts_,
2602 replacement->ToAsciiVector(),
2603 capture_count,
2604 subject_length);
2605 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002606 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002607 AssertNoAllocation no_alloc;
2608
2609 ParseReplacementPattern(&parts_,
2610 replacement->ToUC16Vector(),
2611 capture_count,
2612 subject_length);
2613 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002614 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002615 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002616 int substring_index = 0;
2617 for (int i = 0, n = parts_.length(); i < n; i++) {
2618 int tag = parts_[i].tag;
2619 if (tag <= 0) { // A replacement string slice.
2620 int from = -tag;
2621 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002622 replacement_substrings_.Add(
2623 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002624 parts_[i].tag = REPLACEMENT_SUBSTRING;
2625 parts_[i].data = substring_index;
2626 substring_index++;
2627 } else if (tag == REPLACEMENT_STRING) {
2628 replacement_substrings_.Add(replacement);
2629 parts_[i].data = substring_index;
2630 substring_index++;
2631 }
2632 }
2633}
2634
2635
2636void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2637 int match_from,
2638 int match_to,
2639 Handle<JSArray> last_match_info) {
2640 for (int i = 0, n = parts_.length(); i < n; i++) {
2641 ReplacementPart part = parts_[i];
2642 switch (part.tag) {
2643 case SUBJECT_PREFIX:
2644 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2645 break;
2646 case SUBJECT_SUFFIX: {
2647 int subject_length = part.data;
2648 if (match_to < subject_length) {
2649 builder->AddSubjectSlice(match_to, subject_length);
2650 }
2651 break;
2652 }
2653 case SUBJECT_CAPTURE: {
2654 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002655 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002656 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2657 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2658 if (from >= 0 && to > from) {
2659 builder->AddSubjectSlice(from, to);
2660 }
2661 break;
2662 }
2663 case REPLACEMENT_SUBSTRING:
2664 case REPLACEMENT_STRING:
2665 builder->AddString(replacement_substrings_[part.data]);
2666 break;
2667 default:
2668 UNREACHABLE();
2669 }
2670 }
2671}
2672
2673
2674
lrn@chromium.org303ada72010-10-27 09:33:13 +00002675MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002676 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002677 String* subject,
2678 JSRegExp* regexp,
2679 String* replacement,
2680 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002681 ASSERT(subject->IsFlat());
2682 ASSERT(replacement->IsFlat());
2683
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002684 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002685
2686 int length = subject->length();
2687 Handle<String> subject_handle(subject);
2688 Handle<JSRegExp> regexp_handle(regexp);
2689 Handle<String> replacement_handle(replacement);
2690 Handle<JSArray> last_match_info_handle(last_match_info);
2691 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2692 subject_handle,
2693 0,
2694 last_match_info_handle);
2695 if (match.is_null()) {
2696 return Failure::Exception();
2697 }
2698 if (match->IsNull()) {
2699 return *subject_handle;
2700 }
2701
2702 int capture_count = regexp_handle->CaptureCount();
2703
2704 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002705 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002706 CompiledReplacement compiled_replacement;
2707 compiled_replacement.Compile(replacement_handle,
2708 capture_count,
2709 length);
2710
2711 bool is_global = regexp_handle->GetFlags().is_global();
2712
2713 // Guessing the number of parts that the final result string is built
2714 // from. Global regexps can match any number of times, so we guess
2715 // conservatively.
2716 int expected_parts =
2717 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002718 ReplacementStringBuilder builder(isolate->heap(),
2719 subject_handle,
2720 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002721
2722 // Index of end of last match.
2723 int prev = 0;
2724
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002725 // Number of parts added by compiled replacement plus preceeding
2726 // string and possibly suffix after last match. It is possible for
2727 // all components to use two elements when encoded as two smis.
2728 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002729 bool matched = true;
2730 do {
2731 ASSERT(last_match_info_handle->HasFastElements());
2732 // Increase the capacity of the builder before entering local handle-scope,
2733 // so its internal buffer can safely allocate a new handle if it grows.
2734 builder.EnsureCapacity(parts_added_per_loop);
2735
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002736 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002737 int start, end;
2738 {
2739 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002740 FixedArray* match_info_array =
2741 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002742
2743 ASSERT_EQ(capture_count * 2 + 2,
2744 RegExpImpl::GetLastCaptureCount(match_info_array));
2745 start = RegExpImpl::GetCapture(match_info_array, 0);
2746 end = RegExpImpl::GetCapture(match_info_array, 1);
2747 }
2748
2749 if (prev < start) {
2750 builder.AddSubjectSlice(prev, start);
2751 }
2752 compiled_replacement.Apply(&builder,
2753 start,
2754 end,
2755 last_match_info_handle);
2756 prev = end;
2757
2758 // Only continue checking for global regexps.
2759 if (!is_global) break;
2760
2761 // Continue from where the match ended, unless it was an empty match.
2762 int next = end;
2763 if (start == end) {
2764 next = end + 1;
2765 if (next > length) break;
2766 }
2767
2768 match = RegExpImpl::Exec(regexp_handle,
2769 subject_handle,
2770 next,
2771 last_match_info_handle);
2772 if (match.is_null()) {
2773 return Failure::Exception();
2774 }
2775 matched = !match->IsNull();
2776 } while (matched);
2777
2778 if (prev < length) {
2779 builder.AddSubjectSlice(prev, length);
2780 }
2781
2782 return *(builder.ToString());
2783}
2784
2785
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002786template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002787MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002788 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002789 String* subject,
2790 JSRegExp* regexp,
2791 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002792 ASSERT(subject->IsFlat());
2793
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002794 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002795
2796 Handle<String> subject_handle(subject);
2797 Handle<JSRegExp> regexp_handle(regexp);
2798 Handle<JSArray> last_match_info_handle(last_match_info);
2799 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2800 subject_handle,
2801 0,
2802 last_match_info_handle);
2803 if (match.is_null()) return Failure::Exception();
2804 if (match->IsNull()) return *subject_handle;
2805
2806 ASSERT(last_match_info_handle->HasFastElements());
2807
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002808 int start, end;
2809 {
2810 AssertNoAllocation match_info_array_is_not_in_a_handle;
2811 FixedArray* match_info_array =
2812 FixedArray::cast(last_match_info_handle->elements());
2813
2814 start = RegExpImpl::GetCapture(match_info_array, 0);
2815 end = RegExpImpl::GetCapture(match_info_array, 1);
2816 }
2817
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002818 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002819 int new_length = length - (end - start);
2820 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002821 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002822 }
2823 Handle<ResultSeqString> answer;
2824 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002825 answer = Handle<ResultSeqString>::cast(
2826 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002827 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002828 answer = Handle<ResultSeqString>::cast(
2829 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002830 }
2831
2832 // If the regexp isn't global, only match once.
2833 if (!regexp_handle->GetFlags().is_global()) {
2834 if (start > 0) {
2835 String::WriteToFlat(*subject_handle,
2836 answer->GetChars(),
2837 0,
2838 start);
2839 }
2840 if (end < length) {
2841 String::WriteToFlat(*subject_handle,
2842 answer->GetChars() + start,
2843 end,
2844 length);
2845 }
2846 return *answer;
2847 }
2848
2849 int prev = 0; // Index of end of last match.
2850 int next = 0; // Start of next search (prev unless last match was empty).
2851 int position = 0;
2852
2853 do {
2854 if (prev < start) {
2855 // Add substring subject[prev;start] to answer string.
2856 String::WriteToFlat(*subject_handle,
2857 answer->GetChars() + position,
2858 prev,
2859 start);
2860 position += start - prev;
2861 }
2862 prev = end;
2863 next = end;
2864 // Continue from where the match ended, unless it was an empty match.
2865 if (start == end) {
2866 next++;
2867 if (next > length) break;
2868 }
2869 match = RegExpImpl::Exec(regexp_handle,
2870 subject_handle,
2871 next,
2872 last_match_info_handle);
2873 if (match.is_null()) return Failure::Exception();
2874 if (match->IsNull()) break;
2875
2876 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002877 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002878 {
2879 AssertNoAllocation match_info_array_is_not_in_a_handle;
2880 FixedArray* match_info_array =
2881 FixedArray::cast(last_match_info_handle->elements());
2882 start = RegExpImpl::GetCapture(match_info_array, 0);
2883 end = RegExpImpl::GetCapture(match_info_array, 1);
2884 }
2885 } while (true);
2886
2887 if (prev < length) {
2888 // Add substring subject[prev;length] to answer string.
2889 String::WriteToFlat(*subject_handle,
2890 answer->GetChars() + position,
2891 prev,
2892 length);
2893 position += length - prev;
2894 }
2895
2896 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002897 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002898 }
2899
2900 // Shorten string and fill
2901 int string_size = ResultSeqString::SizeFor(position);
2902 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2903 int delta = allocated_string_size - string_size;
2904
2905 answer->set_length(position);
2906 if (delta == 0) return *answer;
2907
2908 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002909 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002910
2911 return *answer;
2912}
2913
2914
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002915RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002916 ASSERT(args.length() == 4);
2917
2918 CONVERT_CHECKED(String, subject, args[0]);
2919 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002920 Object* flat_subject;
2921 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2922 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2923 return maybe_flat_subject;
2924 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002925 }
2926 subject = String::cast(flat_subject);
2927 }
2928
2929 CONVERT_CHECKED(String, replacement, args[2]);
2930 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002931 Object* flat_replacement;
2932 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2933 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2934 return maybe_flat_replacement;
2935 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002936 }
2937 replacement = String::cast(flat_replacement);
2938 }
2939
2940 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2941 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2942
2943 ASSERT(last_match_info->HasFastElements());
2944
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002945 if (replacement->length() == 0) {
2946 if (subject->HasOnlyAsciiChars()) {
2947 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002948 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002949 } else {
2950 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002951 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002952 }
2953 }
2954
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002955 return StringReplaceRegExpWithString(isolate,
2956 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002957 regexp,
2958 replacement,
2959 last_match_info);
2960}
2961
2962
ager@chromium.org7c537e22008-10-16 08:43:32 +00002963// Perform string match of pattern on subject, starting at start index.
2964// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002965// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002966int Runtime::StringMatch(Isolate* isolate,
2967 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002968 Handle<String> pat,
2969 int start_index) {
2970 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002971 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002972
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002973 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002974 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002975
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002976 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002977 if (start_index + pattern_length > subject_length) return -1;
2978
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002979 if (!sub->IsFlat()) FlattenString(sub);
2980 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002981
ager@chromium.org7c537e22008-10-16 08:43:32 +00002982 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002983 // Extract flattened substrings of cons strings before determining asciiness.
2984 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002985 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002986 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002987 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002988
ager@chromium.org7c537e22008-10-16 08:43:32 +00002989 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002990 if (seq_pat->IsAsciiRepresentation()) {
2991 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2992 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002993 return SearchString(isolate,
2994 seq_sub->ToAsciiVector(),
2995 pat_vector,
2996 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002997 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002998 return SearchString(isolate,
2999 seq_sub->ToUC16Vector(),
3000 pat_vector,
3001 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003002 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003003 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
3004 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003005 return SearchString(isolate,
3006 seq_sub->ToAsciiVector(),
3007 pat_vector,
3008 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003009 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003010 return SearchString(isolate,
3011 seq_sub->ToUC16Vector(),
3012 pat_vector,
3013 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003014}
3015
3016
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003017RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003018 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003019 ASSERT(args.length() == 3);
3020
ager@chromium.org7c537e22008-10-16 08:43:32 +00003021 CONVERT_ARG_CHECKED(String, sub, 0);
3022 CONVERT_ARG_CHECKED(String, pat, 1);
3023
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003024 Object* index = args[2];
3025 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003026 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003027
ager@chromium.org870a0b62008-11-04 11:43:05 +00003028 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003029 int position =
3030 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003031 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003032}
3033
3034
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003035template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003036static int StringMatchBackwards(Vector<const schar> subject,
3037 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003038 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003039 int pattern_length = pattern.length();
3040 ASSERT(pattern_length >= 1);
3041 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003042
3043 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003044 for (int i = 0; i < pattern_length; i++) {
3045 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003046 if (c > String::kMaxAsciiCharCode) {
3047 return -1;
3048 }
3049 }
3050 }
3051
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003052 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003053 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003054 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003055 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003056 while (j < pattern_length) {
3057 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003058 break;
3059 }
3060 j++;
3061 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003062 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003063 return i;
3064 }
3065 }
3066 return -1;
3067}
3068
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003069RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003070 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003071 ASSERT(args.length() == 3);
3072
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003073 CONVERT_ARG_CHECKED(String, sub, 0);
3074 CONVERT_ARG_CHECKED(String, pat, 1);
3075
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003076 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003077 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003078 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003079
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003080 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003081 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003082
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003083 if (start_index + pat_length > sub_length) {
3084 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003085 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003086
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003087 if (pat_length == 0) {
3088 return Smi::FromInt(start_index);
3089 }
3090
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003091 if (!sub->IsFlat()) FlattenString(sub);
3092 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003093
3094 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3095
3096 int position = -1;
3097
3098 if (pat->IsAsciiRepresentation()) {
3099 Vector<const char> pat_vector = pat->ToAsciiVector();
3100 if (sub->IsAsciiRepresentation()) {
3101 position = StringMatchBackwards(sub->ToAsciiVector(),
3102 pat_vector,
3103 start_index);
3104 } else {
3105 position = StringMatchBackwards(sub->ToUC16Vector(),
3106 pat_vector,
3107 start_index);
3108 }
3109 } else {
3110 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3111 if (sub->IsAsciiRepresentation()) {
3112 position = StringMatchBackwards(sub->ToAsciiVector(),
3113 pat_vector,
3114 start_index);
3115 } else {
3116 position = StringMatchBackwards(sub->ToUC16Vector(),
3117 pat_vector,
3118 start_index);
3119 }
3120 }
3121
3122 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003123}
3124
3125
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003126RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003127 NoHandleAllocation ha;
3128 ASSERT(args.length() == 2);
3129
3130 CONVERT_CHECKED(String, str1, args[0]);
3131 CONVERT_CHECKED(String, str2, args[1]);
3132
3133 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003134 int str1_length = str1->length();
3135 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003136
3137 // Decide trivial cases without flattening.
3138 if (str1_length == 0) {
3139 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3140 return Smi::FromInt(-str2_length);
3141 } else {
3142 if (str2_length == 0) return Smi::FromInt(str1_length);
3143 }
3144
3145 int end = str1_length < str2_length ? str1_length : str2_length;
3146
3147 // No need to flatten if we are going to find the answer on the first
3148 // character. At this point we know there is at least one character
3149 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003150 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003151 if (d != 0) return Smi::FromInt(d);
3152
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003153 str1->TryFlatten();
3154 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003155
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003156 StringInputBuffer& buf1 =
3157 *isolate->runtime_state()->string_locale_compare_buf1();
3158 StringInputBuffer& buf2 =
3159 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003160
3161 buf1.Reset(str1);
3162 buf2.Reset(str2);
3163
3164 for (int i = 0; i < end; i++) {
3165 uint16_t char1 = buf1.GetNext();
3166 uint16_t char2 = buf2.GetNext();
3167 if (char1 != char2) return Smi::FromInt(char1 - char2);
3168 }
3169
3170 return Smi::FromInt(str1_length - str2_length);
3171}
3172
3173
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003174RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003175 NoHandleAllocation ha;
3176 ASSERT(args.length() == 3);
3177
3178 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003179 int start, end;
3180 // We have a fast integer-only case here to avoid a conversion to double in
3181 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003182 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3183 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3184 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3185 start = from_number;
3186 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003187 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003188 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3189 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003190 start = FastD2I(from_number);
3191 end = FastD2I(to_number);
3192 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003193 RUNTIME_ASSERT(end >= start);
3194 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003195 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003196 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003197 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003198}
3199
3200
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003201RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003202 ASSERT_EQ(3, args.length());
3203
3204 CONVERT_ARG_CHECKED(String, subject, 0);
3205 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3206 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3207 HandleScope handles;
3208
3209 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3210
3211 if (match.is_null()) {
3212 return Failure::Exception();
3213 }
3214 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003215 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003216 }
3217 int length = subject->length();
3218
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003219 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003220 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003221 int start;
3222 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003223 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003224 {
3225 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003226 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003227 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3228 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3229 }
3230 offsets.Add(start);
3231 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003232 if (start == end) if (++end > length) break;
3233 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003234 if (match.is_null()) {
3235 return Failure::Exception();
3236 }
3237 } while (!match->IsNull());
3238 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003239 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003240 Handle<String> substring = isolate->factory()->
3241 NewSubString(subject, offsets.at(0), offsets.at(1));
3242 elements->set(0, *substring);
3243 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003244 int from = offsets.at(i * 2);
3245 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003246 Handle<String> substring = isolate->factory()->
3247 NewProperSubString(subject, from, to);
3248 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003249 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003250 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003251 result->set_length(Smi::FromInt(matches));
3252 return *result;
3253}
3254
3255
lrn@chromium.org25156de2010-04-06 13:10:27 +00003256// Two smis before and after the match, for very long strings.
3257const int kMaxBuilderEntriesPerRegExpMatch = 5;
3258
3259
3260static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3261 Handle<JSArray> last_match_info,
3262 int match_start,
3263 int match_end) {
3264 // Fill last_match_info with a single capture.
3265 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3266 AssertNoAllocation no_gc;
3267 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3268 RegExpImpl::SetLastCaptureCount(elements, 2);
3269 RegExpImpl::SetLastInput(elements, *subject);
3270 RegExpImpl::SetLastSubject(elements, *subject);
3271 RegExpImpl::SetCapture(elements, 0, match_start);
3272 RegExpImpl::SetCapture(elements, 1, match_end);
3273}
3274
3275
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003276template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003277static bool SearchStringMultiple(Isolate* isolate,
3278 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003279 Vector<const PatternChar> pattern,
3280 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003281 FixedArrayBuilder* builder,
3282 int* match_pos) {
3283 int pos = *match_pos;
3284 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003285 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003286 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003287 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003288 while (pos <= max_search_start) {
3289 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3290 *match_pos = pos;
3291 return false;
3292 }
3293 // Position of end of previous match.
3294 int match_end = pos + pattern_length;
3295 int new_pos = search.Search(subject, match_end);
3296 if (new_pos >= 0) {
3297 // A match.
3298 if (new_pos > match_end) {
3299 ReplacementStringBuilder::AddSubjectSlice(builder,
3300 match_end,
3301 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003302 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003303 pos = new_pos;
3304 builder->Add(pattern_string);
3305 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003306 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003307 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003308 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003309
lrn@chromium.org25156de2010-04-06 13:10:27 +00003310 if (pos < max_search_start) {
3311 ReplacementStringBuilder::AddSubjectSlice(builder,
3312 pos + pattern_length,
3313 subject_length);
3314 }
3315 *match_pos = pos;
3316 return true;
3317}
3318
3319
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003320static bool SearchStringMultiple(Isolate* isolate,
3321 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003322 Handle<String> pattern,
3323 Handle<JSArray> last_match_info,
3324 FixedArrayBuilder* builder) {
3325 ASSERT(subject->IsFlat());
3326 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003327
3328 // Treating as if a previous match was before first character.
3329 int match_pos = -pattern->length();
3330
3331 for (;;) { // Break when search complete.
3332 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3333 AssertNoAllocation no_gc;
3334 if (subject->IsAsciiRepresentation()) {
3335 Vector<const char> subject_vector = subject->ToAsciiVector();
3336 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003337 if (SearchStringMultiple(isolate,
3338 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003339 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003340 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003341 builder,
3342 &match_pos)) break;
3343 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003344 if (SearchStringMultiple(isolate,
3345 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003346 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003347 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003348 builder,
3349 &match_pos)) break;
3350 }
3351 } else {
3352 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3353 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003354 if (SearchStringMultiple(isolate,
3355 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003356 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003357 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003358 builder,
3359 &match_pos)) break;
3360 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003361 if (SearchStringMultiple(isolate,
3362 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003363 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003364 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003365 builder,
3366 &match_pos)) break;
3367 }
3368 }
3369 }
3370
3371 if (match_pos >= 0) {
3372 SetLastMatchInfoNoCaptures(subject,
3373 last_match_info,
3374 match_pos,
3375 match_pos + pattern->length());
3376 return true;
3377 }
3378 return false; // No matches at all.
3379}
3380
3381
3382static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003383 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003384 Handle<String> subject,
3385 Handle<JSRegExp> regexp,
3386 Handle<JSArray> last_match_array,
3387 FixedArrayBuilder* builder) {
3388 ASSERT(subject->IsFlat());
3389 int match_start = -1;
3390 int match_end = 0;
3391 int pos = 0;
3392 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3393 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3394
3395 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003396 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003397 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003398 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003399
3400 for (;;) { // Break on failure, return on exception.
3401 RegExpImpl::IrregexpResult result =
3402 RegExpImpl::IrregexpExecOnce(regexp,
3403 subject,
3404 pos,
3405 register_vector);
3406 if (result == RegExpImpl::RE_SUCCESS) {
3407 match_start = register_vector[0];
3408 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3409 if (match_end < match_start) {
3410 ReplacementStringBuilder::AddSubjectSlice(builder,
3411 match_end,
3412 match_start);
3413 }
3414 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003415 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003416 if (!first) {
3417 builder->Add(*isolate->factory()->NewProperSubString(subject,
3418 match_start,
3419 match_end));
3420 } else {
3421 builder->Add(*isolate->factory()->NewSubString(subject,
3422 match_start,
3423 match_end));
3424 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003425 if (match_start != match_end) {
3426 pos = match_end;
3427 } else {
3428 pos = match_end + 1;
3429 if (pos > subject_length) break;
3430 }
3431 } else if (result == RegExpImpl::RE_FAILURE) {
3432 break;
3433 } else {
3434 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3435 return result;
3436 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003437 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003438 }
3439
3440 if (match_start >= 0) {
3441 if (match_end < subject_length) {
3442 ReplacementStringBuilder::AddSubjectSlice(builder,
3443 match_end,
3444 subject_length);
3445 }
3446 SetLastMatchInfoNoCaptures(subject,
3447 last_match_array,
3448 match_start,
3449 match_end);
3450 return RegExpImpl::RE_SUCCESS;
3451 } else {
3452 return RegExpImpl::RE_FAILURE; // No matches at all.
3453 }
3454}
3455
3456
3457static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003458 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003459 Handle<String> subject,
3460 Handle<JSRegExp> regexp,
3461 Handle<JSArray> last_match_array,
3462 FixedArrayBuilder* builder) {
3463
3464 ASSERT(subject->IsFlat());
3465 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3466 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3467
3468 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003469 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003470
3471 RegExpImpl::IrregexpResult result =
3472 RegExpImpl::IrregexpExecOnce(regexp,
3473 subject,
3474 0,
3475 register_vector);
3476
3477 int capture_count = regexp->CaptureCount();
3478 int subject_length = subject->length();
3479
3480 // Position to search from.
3481 int pos = 0;
3482 // End of previous match. Differs from pos if match was empty.
3483 int match_end = 0;
3484 if (result == RegExpImpl::RE_SUCCESS) {
3485 // Need to keep a copy of the previous match for creating last_match_info
3486 // at the end, so we have two vectors that we swap between.
3487 OffsetsVector registers2(required_registers);
3488 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003489 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003490 do {
3491 int match_start = register_vector[0];
3492 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3493 if (match_end < match_start) {
3494 ReplacementStringBuilder::AddSubjectSlice(builder,
3495 match_end,
3496 match_start);
3497 }
3498 match_end = register_vector[1];
3499
3500 {
3501 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003502 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003503 // Arguments array to replace function is match, captures, index and
3504 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003505 Handle<FixedArray> elements =
3506 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003507 Handle<String> match;
3508 if (!first) {
3509 match = isolate->factory()->NewProperSubString(subject,
3510 match_start,
3511 match_end);
3512 } else {
3513 match = isolate->factory()->NewSubString(subject,
3514 match_start,
3515 match_end);
3516 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003517 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003518 for (int i = 1; i <= capture_count; i++) {
3519 int start = register_vector[i * 2];
3520 if (start >= 0) {
3521 int end = register_vector[i * 2 + 1];
3522 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003523 Handle<String> substring;
3524 if (!first) {
3525 substring = isolate->factory()->NewProperSubString(subject,
3526 start,
3527 end);
3528 } else {
3529 substring = isolate->factory()->NewSubString(subject, start, end);
3530 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003531 elements->set(i, *substring);
3532 } else {
3533 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003534 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003535 }
3536 }
3537 elements->set(capture_count + 1, Smi::FromInt(match_start));
3538 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003539 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003540 }
3541 // Swap register vectors, so the last successful match is in
3542 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003543 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003544 prev_register_vector = register_vector;
3545 register_vector = tmp;
3546
3547 if (match_end > match_start) {
3548 pos = match_end;
3549 } else {
3550 pos = match_end + 1;
3551 if (pos > subject_length) {
3552 break;
3553 }
3554 }
3555
3556 result = RegExpImpl::IrregexpExecOnce(regexp,
3557 subject,
3558 pos,
3559 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003560 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003561 } while (result == RegExpImpl::RE_SUCCESS);
3562
3563 if (result != RegExpImpl::RE_EXCEPTION) {
3564 // Finished matching, with at least one match.
3565 if (match_end < subject_length) {
3566 ReplacementStringBuilder::AddSubjectSlice(builder,
3567 match_end,
3568 subject_length);
3569 }
3570
3571 int last_match_capture_count = (capture_count + 1) * 2;
3572 int last_match_array_size =
3573 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3574 last_match_array->EnsureSize(last_match_array_size);
3575 AssertNoAllocation no_gc;
3576 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3577 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3578 RegExpImpl::SetLastSubject(elements, *subject);
3579 RegExpImpl::SetLastInput(elements, *subject);
3580 for (int i = 0; i < last_match_capture_count; i++) {
3581 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3582 }
3583 return RegExpImpl::RE_SUCCESS;
3584 }
3585 }
3586 // No matches at all, return failure or exception result directly.
3587 return result;
3588}
3589
3590
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003591RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003592 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003593 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003594
3595 CONVERT_ARG_CHECKED(String, subject, 1);
3596 if (!subject->IsFlat()) { FlattenString(subject); }
3597 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3598 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3599 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3600
3601 ASSERT(last_match_info->HasFastElements());
3602 ASSERT(regexp->GetFlags().is_global());
3603 Handle<FixedArray> result_elements;
3604 if (result_array->HasFastElements()) {
3605 result_elements =
3606 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003607 }
3608 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003609 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003610 }
3611 FixedArrayBuilder builder(result_elements);
3612
3613 if (regexp->TypeTag() == JSRegExp::ATOM) {
3614 Handle<String> pattern(
3615 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003616 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003617 if (SearchStringMultiple(isolate, subject, pattern,
3618 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003619 return *builder.ToJSArray(result_array);
3620 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003621 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003622 }
3623
3624 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3625
3626 RegExpImpl::IrregexpResult result;
3627 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003628 result = SearchRegExpNoCaptureMultiple(isolate,
3629 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003630 regexp,
3631 last_match_info,
3632 &builder);
3633 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003634 result = SearchRegExpMultiple(isolate,
3635 subject,
3636 regexp,
3637 last_match_info,
3638 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003639 }
3640 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003641 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003642 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3643 return Failure::Exception();
3644}
3645
3646
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003647RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003648 NoHandleAllocation ha;
3649 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003650 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003651 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003652
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003653 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003654 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003655 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003656 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003657 // Character array used for conversion.
3658 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003659 return isolate->heap()->
3660 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003661 }
3662 }
3663
3664 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003665 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003666 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003667 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003668 }
3669 if (isinf(value)) {
3670 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003671 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003672 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003673 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003674 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003675 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003676 MaybeObject* result =
3677 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003678 DeleteArray(str);
3679 return result;
3680}
3681
3682
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003683RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003684 NoHandleAllocation ha;
3685 ASSERT(args.length() == 2);
3686
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003687 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003688 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003689 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003690 }
3691 if (isinf(value)) {
3692 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003693 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003694 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003695 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003696 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003697 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003698 int f = FastD2I(f_number);
3699 RUNTIME_ASSERT(f >= 0);
3700 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003701 MaybeObject* res =
3702 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003703 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003704 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003705}
3706
3707
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003708RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003709 NoHandleAllocation ha;
3710 ASSERT(args.length() == 2);
3711
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003712 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003713 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003714 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003715 }
3716 if (isinf(value)) {
3717 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003718 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003719 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003720 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003721 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003722 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003723 int f = FastD2I(f_number);
3724 RUNTIME_ASSERT(f >= -1 && f <= 20);
3725 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003726 MaybeObject* res =
3727 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003728 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003729 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003730}
3731
3732
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003733RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003734 NoHandleAllocation ha;
3735 ASSERT(args.length() == 2);
3736
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003737 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003738 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003739 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003740 }
3741 if (isinf(value)) {
3742 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003743 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003744 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003745 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003746 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003747 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003748 int f = FastD2I(f_number);
3749 RUNTIME_ASSERT(f >= 1 && f <= 21);
3750 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003751 MaybeObject* res =
3752 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003753 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003754 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003755}
3756
3757
3758// Returns a single character string where first character equals
3759// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003760static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003761 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003762 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003763 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003764 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003765 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003766 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003767}
3768
3769
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003770MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3771 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003772 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003773 // Handle [] indexing on Strings
3774 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003775 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3776 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003777 }
3778
3779 // Handle [] indexing on String objects
3780 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003781 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3782 Handle<Object> result =
3783 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3784 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003785 }
3786
3787 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003788 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003789 return prototype->GetElement(index);
3790 }
3791
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003792 return GetElement(object, index);
3793}
3794
3795
lrn@chromium.org303ada72010-10-27 09:33:13 +00003796MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003797 return object->GetElement(index);
3798}
3799
3800
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003801MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3802 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003803 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003804 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003805
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003806 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003807 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003808 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003809 isolate->factory()->NewTypeError("non_object_property_load",
3810 HandleVector(args, 2));
3811 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003812 }
3813
3814 // Check if the given key is an array index.
3815 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003816 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003817 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003818 }
3819
3820 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003821 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003822 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003823 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003824 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003825 bool has_pending_exception = false;
3826 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003827 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003828 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003829 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003830 }
3831
ager@chromium.org32912102009-01-16 10:38:43 +00003832 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003833 // the element if so.
3834 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003835 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003836 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003837 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003838 }
3839}
3840
3841
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003842RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003843 NoHandleAllocation ha;
3844 ASSERT(args.length() == 2);
3845
3846 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003847 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003848
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003849 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003850}
3851
3852
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003853// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003854RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003855 NoHandleAllocation ha;
3856 ASSERT(args.length() == 2);
3857
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003858 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003859 // itself.
3860 //
3861 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003862 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003863 // global proxy object never has properties. This is the case
3864 // because the global proxy object forwards everything to its hidden
3865 // prototype including local lookups.
3866 //
3867 // Additionally, we need to make sure that we do not cache results
3868 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003869 if (args[0]->IsJSObject() &&
3870 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003871 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003872 args[1]->IsString()) {
3873 JSObject* receiver = JSObject::cast(args[0]);
3874 String* key = String::cast(args[1]);
3875 if (receiver->HasFastProperties()) {
3876 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003877 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003878 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3879 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003880 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003881 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003882 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003883 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003884 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003885 LookupResult result;
3886 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003887 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003888 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003889 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003890 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003891 }
3892 } else {
3893 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003894 StringDictionary* dictionary = receiver->property_dictionary();
3895 int entry = dictionary->FindEntry(key);
3896 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003897 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003898 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003899 if (!receiver->IsGlobalObject()) return value;
3900 value = JSGlobalPropertyCell::cast(value)->value();
3901 if (!value->IsTheHole()) return value;
3902 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003903 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003904 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003905 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3906 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003907 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003908 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003909 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003910 if (index >= 0 && index < str->length()) {
3911 Handle<Object> result = GetCharAt(str, index);
3912 return *result;
3913 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003914 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003915
3916 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003917 return Runtime::GetObjectProperty(isolate,
3918 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003919 args.at<Object>(1));
3920}
3921
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003922// Implements part of 8.12.9 DefineOwnProperty.
3923// There are 3 cases that lead here:
3924// Step 4b - define a new accessor property.
3925// Steps 9c & 12 - replace an existing data property with an accessor property.
3926// Step 12 - update an existing accessor property with an accessor or generic
3927// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003928RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003929 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003930 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003931 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3932 CONVERT_CHECKED(String, name, args[1]);
3933 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003934 Object* fun = args[3];
3935 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003936 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3937 int unchecked = flag_attr->value();
3938 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3939 RUNTIME_ASSERT(!obj->IsNull());
3940 LookupResult result;
3941 obj->LocalLookupRealNamedProperty(name, &result);
3942
3943 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3944 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3945 // delete it to avoid running into trouble in DefineAccessor, which
3946 // handles this incorrectly if the property is readonly (does nothing)
3947 if (result.IsProperty() &&
3948 (result.type() == FIELD || result.type() == NORMAL
3949 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003950 Object* ok;
3951 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003952 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003953 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3954 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003955 }
3956 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3957}
3958
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003959// Implements part of 8.12.9 DefineOwnProperty.
3960// There are 3 cases that lead here:
3961// Step 4a - define a new data property.
3962// Steps 9b & 12 - replace an existing accessor property with a data property.
3963// Step 12 - update an existing data property with a data or generic
3964// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003965RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003966 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003967 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003968 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3969 CONVERT_ARG_CHECKED(String, name, 1);
3970 Handle<Object> obj_value = args.at<Object>(2);
3971
3972 CONVERT_CHECKED(Smi, flag, args[3]);
3973 int unchecked = flag->value();
3974 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3975
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003976 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3977
3978 // Check if this is an element.
3979 uint32_t index;
3980 bool is_element = name->AsArrayIndex(&index);
3981
3982 // Special case for elements if any of the flags are true.
3983 // If elements are in fast case we always implicitly assume that:
3984 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3985 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3986 is_element) {
3987 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003988 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003989 // We do not need to do access checks here since these has already
3990 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003991 Handle<Object> proto(js_object->GetPrototype());
3992 // If proxy is detached, ignore the assignment. Alternatively,
3993 // we could throw an exception.
3994 if (proto->IsNull()) return *obj_value;
3995 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003996 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003997 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003998 // Make sure that we never go back to fast case.
3999 dictionary->set_requires_slow_elements();
4000 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004001 Handle<NumberDictionary> extended_dictionary =
4002 NumberDictionarySet(dictionary, index, obj_value, details);
4003 if (*extended_dictionary != *dictionary) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004004 if (js_object->GetElementsKind() ==
4005 JSObject::NON_STRICT_ARGUMENTS_ELEMENTS) {
4006 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4007 } else {
4008 js_object->set_elements(*extended_dictionary);
4009 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004010 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004011 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004012 }
4013
ager@chromium.org5c838252010-02-19 08:53:10 +00004014 LookupResult result;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004015 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004016
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004017 // To be compatible with safari we do not change the value on API objects
4018 // in defineProperty. Firefox disagrees here, and actually changes the value.
4019 if (result.IsProperty() &&
4020 (result.type() == CALLBACKS) &&
4021 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004022 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004023 }
4024
ager@chromium.org5c838252010-02-19 08:53:10 +00004025 // Take special care when attributes are different and there is already
4026 // a property. For simplicity we normalize the property which enables us
4027 // to not worry about changing the instance_descriptor and creating a new
4028 // map. The current version of SetObjectProperty does not handle attributes
4029 // correctly in the case where a property is a field and is reset with
4030 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004031 if (result.IsProperty() &&
4032 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004033 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004034 if (js_object->IsJSGlobalProxy()) {
4035 // Since the result is a property, the prototype will exist so
4036 // we don't have to check for null.
4037 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004038 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004039 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004040 // Use IgnoreAttributes version since a readonly property may be
4041 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004042 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4043 *obj_value,
4044 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004045 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004046
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004047 return Runtime::ForceSetObjectProperty(isolate,
4048 js_object,
4049 name,
4050 obj_value,
4051 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004052}
4053
4054
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004055// Special case for elements if any of the flags are true.
4056// If elements are in fast case we always implicitly assume that:
4057// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4058static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4059 Handle<JSObject> js_object,
4060 uint32_t index,
4061 Handle<Object> value,
4062 PropertyAttributes attr) {
4063 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004064 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004065 // Make sure that we never go back to fast case.
4066 dictionary->set_requires_slow_elements();
4067 PropertyDetails details = PropertyDetails(attr, NORMAL);
4068 Handle<NumberDictionary> extended_dictionary =
4069 NumberDictionarySet(dictionary, index, value, details);
4070 if (*extended_dictionary != *dictionary) {
4071 js_object->set_elements(*extended_dictionary);
4072 }
4073 return *value;
4074}
4075
4076
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004077MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4078 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004079 Handle<Object> key,
4080 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004081 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004082 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004083 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004084
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004085 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004086 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004087 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004088 isolate->factory()->NewTypeError("non_object_property_store",
4089 HandleVector(args, 2));
4090 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004091 }
4092
4093 // If the object isn't a JavaScript object, we ignore the store.
4094 if (!object->IsJSObject()) return *value;
4095
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004096 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4097
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004098 // Check if the given key is an array index.
4099 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004100 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004101 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4102 // of a string using [] notation. We need to support this too in
4103 // JavaScript.
4104 // In the case of a String object we just need to redirect the assignment to
4105 // the underlying string if the index is in range. Since the underlying
4106 // string does nothing with the assignment then we can ignore such
4107 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004108 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004110 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004111
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004112 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4113 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4114 }
4115
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004116 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004117 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004118 return *value;
4119 }
4120
4121 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004122 Handle<Object> result;
4123 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004124 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4125 return NormalizeObjectSetElement(isolate,
4126 js_object,
4127 index,
4128 value,
4129 attr);
4130 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004131 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004132 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004133 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004134 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004135 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004136 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004137 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004138 return *value;
4139 }
4140
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004141 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004142 bool has_pending_exception = false;
4143 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4144 if (has_pending_exception) return Failure::Exception();
4145 Handle<String> name = Handle<String>::cast(converted);
4146
4147 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004148 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004149 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004150 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004151 }
4152}
4153
4154
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004155MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4156 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004157 Handle<Object> key,
4158 Handle<Object> value,
4159 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004160 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004161
4162 // Check if the given key is an array index.
4163 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004164 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004165 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4166 // of a string using [] notation. We need to support this too in
4167 // JavaScript.
4168 // In the case of a String object we just need to redirect the assignment to
4169 // the underlying string if the index is in range. Since the underlying
4170 // string does nothing with the assignment then we can ignore such
4171 // assignments.
4172 if (js_object->IsStringObjectWithCharacterAt(index)) {
4173 return *value;
4174 }
4175
whesse@chromium.org7b260152011-06-20 15:33:18 +00004176 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004177 }
4178
4179 if (key->IsString()) {
4180 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004181 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004182 } else {
4183 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004184 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004185 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4186 *value,
4187 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004188 }
4189 }
4190
4191 // Call-back into JavaScript to convert the key to a string.
4192 bool has_pending_exception = false;
4193 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4194 if (has_pending_exception) return Failure::Exception();
4195 Handle<String> name = Handle<String>::cast(converted);
4196
4197 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004198 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004199 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004200 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004201 }
4202}
4203
4204
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004205MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004206 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004207 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004208 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004209
4210 // Check if the given key is an array index.
4211 uint32_t index;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004212 if (receiver->IsJSObject() && key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004213 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4214 // characters of a string using [] notation. In the case of a
4215 // String object we just need to redirect the deletion to the
4216 // underlying string if the index is in range. Since the
4217 // underlying string does nothing with the deletion, we can ignore
4218 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004219 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004220 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004221 }
4222
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004223 return JSObject::cast(*receiver)->DeleteElement(
4224 index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004225 }
4226
4227 Handle<String> key_string;
4228 if (key->IsString()) {
4229 key_string = Handle<String>::cast(key);
4230 } else {
4231 // Call-back into JavaScript to convert the key to a string.
4232 bool has_pending_exception = false;
4233 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4234 if (has_pending_exception) return Failure::Exception();
4235 key_string = Handle<String>::cast(converted);
4236 }
4237
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004238 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004239 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004240}
4241
4242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004243RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004244 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004245 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004246
4247 Handle<Object> object = args.at<Object>(0);
4248 Handle<Object> key = args.at<Object>(1);
4249 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004250 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004251 RUNTIME_ASSERT(
4252 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004253 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004254 PropertyAttributes attributes =
4255 static_cast<PropertyAttributes>(unchecked_attributes);
4256
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004257 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004258 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004259 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004260 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4261 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004262 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004263 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004264
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004265 return Runtime::SetObjectProperty(isolate,
4266 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004267 key,
4268 value,
4269 attributes,
4270 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004271}
4272
4273
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004274// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004275// This is used to decide if we should transform null and undefined
4276// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004277RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004278 NoHandleAllocation ha;
4279 RUNTIME_ASSERT(args.length() == 1);
4280
4281 Handle<Object> object = args.at<Object>(0);
4282
4283 if (object->IsJSFunction()) {
4284 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004285 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004286 }
4287 return isolate->heap()->undefined_value();
4288}
4289
4290
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004291// Set a local property, even if it is READ_ONLY. If the property does not
4292// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004293RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004294 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004295 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004296 CONVERT_CHECKED(JSObject, object, args[0]);
4297 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004298 // Compute attributes.
4299 PropertyAttributes attributes = NONE;
4300 if (args.length() == 4) {
4301 CONVERT_CHECKED(Smi, value_obj, args[3]);
4302 int unchecked_value = value_obj->value();
4303 // Only attribute bits should be set.
4304 RUNTIME_ASSERT(
4305 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4306 attributes = static_cast<PropertyAttributes>(unchecked_value);
4307 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004308
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004309 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004310 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004311}
4312
4313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004314RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004315 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004316 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004317
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004318 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004319 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004320 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004321 return object->DeleteProperty(key, (strict == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004322 ? JSReceiver::STRICT_DELETION
4323 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004324}
4325
4326
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004327static Object* HasLocalPropertyImplementation(Isolate* isolate,
4328 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004329 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004330 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004331 // Handle hidden prototypes. If there's a hidden prototype above this thing
4332 // then we have to check it for properties, because they are supposed to
4333 // look like they are on this object.
4334 Handle<Object> proto(object->GetPrototype());
4335 if (proto->IsJSObject() &&
4336 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004337 return HasLocalPropertyImplementation(isolate,
4338 Handle<JSObject>::cast(proto),
4339 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004340 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004341 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004342}
4343
4344
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004345RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004346 NoHandleAllocation ha;
4347 ASSERT(args.length() == 2);
4348 CONVERT_CHECKED(String, key, args[1]);
4349
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004350 uint32_t index;
4351 const bool key_is_array_index = key->AsArrayIndex(&index);
4352
ager@chromium.org9085a012009-05-11 19:22:57 +00004353 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004354 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004355 if (obj->IsJSObject()) {
4356 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004357 // Fast case: either the key is a real named property or it is not
4358 // an array index and there are no interceptors or hidden
4359 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004360 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004361 Map* map = object->map();
4362 if (!key_is_array_index &&
4363 !map->has_named_interceptor() &&
4364 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4365 return isolate->heap()->false_value();
4366 }
4367 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004368 HandleScope scope(isolate);
4369 return HasLocalPropertyImplementation(isolate,
4370 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004371 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004372 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004373 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004374 String* string = String::cast(obj);
4375 if (index < static_cast<uint32_t>(string->length())) {
4376 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004377 }
4378 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004379 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004380}
4381
4382
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004383RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004384 NoHandleAllocation na;
4385 ASSERT(args.length() == 2);
4386
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004387 // Only JS receivers can have properties.
4388 if (args[0]->IsJSReceiver()) {
4389 JSReceiver* receiver = JSReceiver::cast(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004390 CONVERT_CHECKED(String, key, args[1]);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004391 if (receiver->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004392 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004393 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004394}
4395
4396
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004397RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004398 NoHandleAllocation na;
4399 ASSERT(args.length() == 2);
4400
4401 // Only JS objects can have elements.
4402 if (args[0]->IsJSObject()) {
4403 JSObject* object = JSObject::cast(args[0]);
4404 CONVERT_CHECKED(Smi, index_obj, args[1]);
4405 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004406 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004407 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004408 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004409}
4410
4411
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004412RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004413 NoHandleAllocation ha;
4414 ASSERT(args.length() == 2);
4415
4416 CONVERT_CHECKED(JSObject, object, args[0]);
4417 CONVERT_CHECKED(String, key, args[1]);
4418
4419 uint32_t index;
4420 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004421 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004422 }
4423
ager@chromium.org870a0b62008-11-04 11:43:05 +00004424 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004425 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004426}
4427
4428
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004429RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004430 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004431 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004432 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004433 return *GetKeysFor(object);
4434}
4435
4436
4437// Returns either a FixedArray as Runtime_GetPropertyNames,
4438// or, if the given object has an enum cache that contains
4439// all enumerable properties of the object and its prototypes
4440// have none, the map of the object. This is used to speed up
4441// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004442RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004443 ASSERT(args.length() == 1);
4444
4445 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4446
4447 if (raw_object->IsSimpleEnum()) return raw_object->map();
4448
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004449 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004450 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004451 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4452 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004453
4454 // Test again, since cache may have been built by preceding call.
4455 if (object->IsSimpleEnum()) return object->map();
4456
4457 return *content;
4458}
4459
4460
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004461// Find the length of the prototype chain that is to to handled as one. If a
4462// prototype object is hidden it is to be viewed as part of the the object it
4463// is prototype for.
4464static int LocalPrototypeChainLength(JSObject* obj) {
4465 int count = 1;
4466 Object* proto = obj->GetPrototype();
4467 while (proto->IsJSObject() &&
4468 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4469 count++;
4470 proto = JSObject::cast(proto)->GetPrototype();
4471 }
4472 return count;
4473}
4474
4475
4476// Return the names of the local named properties.
4477// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004478RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004479 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004480 ASSERT(args.length() == 1);
4481 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004482 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004483 }
4484 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4485
4486 // Skip the global proxy as it has no properties and always delegates to the
4487 // real global object.
4488 if (obj->IsJSGlobalProxy()) {
4489 // Only collect names if access is permitted.
4490 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004491 !isolate->MayNamedAccess(*obj,
4492 isolate->heap()->undefined_value(),
4493 v8::ACCESS_KEYS)) {
4494 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4495 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004496 }
4497 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4498 }
4499
4500 // Find the number of objects making up this.
4501 int length = LocalPrototypeChainLength(*obj);
4502
4503 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004504 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004505 int total_property_count = 0;
4506 Handle<JSObject> jsproto = obj;
4507 for (int i = 0; i < length; i++) {
4508 // Only collect names if access is permitted.
4509 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004510 !isolate->MayNamedAccess(*jsproto,
4511 isolate->heap()->undefined_value(),
4512 v8::ACCESS_KEYS)) {
4513 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4514 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004515 }
4516 int n;
4517 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4518 local_property_count[i] = n;
4519 total_property_count += n;
4520 if (i < length - 1) {
4521 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4522 }
4523 }
4524
4525 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004526 Handle<FixedArray> names =
4527 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004528
4529 // Get the property names.
4530 jsproto = obj;
4531 int proto_with_hidden_properties = 0;
4532 for (int i = 0; i < length; i++) {
4533 jsproto->GetLocalPropertyNames(*names,
4534 i == 0 ? 0 : local_property_count[i - 1]);
4535 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4536 proto_with_hidden_properties++;
4537 }
4538 if (i < length - 1) {
4539 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4540 }
4541 }
4542
4543 // Filter out name of hidden propeties object.
4544 if (proto_with_hidden_properties > 0) {
4545 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004546 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004547 names->length() - proto_with_hidden_properties);
4548 int dest_pos = 0;
4549 for (int i = 0; i < total_property_count; i++) {
4550 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004551 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004552 continue;
4553 }
4554 names->set(dest_pos++, name);
4555 }
4556 }
4557
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004558 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004559}
4560
4561
4562// Return the names of the local indexed properties.
4563// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004564RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004565 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004566 ASSERT(args.length() == 1);
4567 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004568 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004569 }
4570 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4571
4572 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004573 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004574 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004575 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004576}
4577
4578
4579// Return information on whether an object has a named or indexed interceptor.
4580// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004581RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004582 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004583 ASSERT(args.length() == 1);
4584 if (!args[0]->IsJSObject()) {
4585 return Smi::FromInt(0);
4586 }
4587 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4588
4589 int result = 0;
4590 if (obj->HasNamedInterceptor()) result |= 2;
4591 if (obj->HasIndexedInterceptor()) result |= 1;
4592
4593 return Smi::FromInt(result);
4594}
4595
4596
4597// Return property names from named interceptor.
4598// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004599RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004600 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004601 ASSERT(args.length() == 1);
4602 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4603
4604 if (obj->HasNamedInterceptor()) {
4605 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4606 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4607 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004608 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004609}
4610
4611
4612// Return element names from indexed interceptor.
4613// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004614RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004615 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004616 ASSERT(args.length() == 1);
4617 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4618
4619 if (obj->HasIndexedInterceptor()) {
4620 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4621 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4622 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004623 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004624}
4625
4626
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004627RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004628 ASSERT_EQ(args.length(), 1);
4629 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004630 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004631 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004632
4633 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004634 // Do access checks before going to the global object.
4635 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004636 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004637 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004638 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4639 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004640 }
4641
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004642 Handle<Object> proto(object->GetPrototype());
4643 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004644 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004645 object = Handle<JSObject>::cast(proto);
4646 }
4647
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004648 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4649 LOCAL_ONLY);
4650 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4651 // property array and since the result is mutable we have to create
4652 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004653 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004654 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004655 for (int i = 0; i < length; i++) {
4656 Object* entry = contents->get(i);
4657 if (entry->IsString()) {
4658 copy->set(i, entry);
4659 } else {
4660 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004661 HandleScope scope(isolate);
4662 Handle<Object> entry_handle(entry, isolate);
4663 Handle<Object> entry_str =
4664 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004665 copy->set(i, *entry_str);
4666 }
4667 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004668 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004669}
4670
4671
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004672RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004673 NoHandleAllocation ha;
4674 ASSERT(args.length() == 1);
4675
4676 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004677 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004678 it.AdvanceToArgumentsFrame();
4679 JavaScriptFrame* frame = it.frame();
4680
4681 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004682 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004683
4684 // Try to convert the key to an index. If successful and within
4685 // index return the the argument from the frame.
4686 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004687 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004688 return frame->GetParameter(index);
4689 }
4690
4691 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004692 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004693 bool exception = false;
4694 Handle<Object> converted =
4695 Execution::ToString(args.at<Object>(0), &exception);
4696 if (exception) return Failure::Exception();
4697 Handle<String> key = Handle<String>::cast(converted);
4698
4699 // Try to convert the string key into an array index.
4700 if (key->AsArrayIndex(&index)) {
4701 if (index < n) {
4702 return frame->GetParameter(index);
4703 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004704 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004705 }
4706 }
4707
4708 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004709 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4710 if (key->Equals(isolate->heap()->callee_symbol())) {
4711 Object* function = frame->function();
4712 if (function->IsJSFunction() &&
4713 JSFunction::cast(function)->shared()->strict_mode()) {
4714 return isolate->Throw(*isolate->factory()->NewTypeError(
4715 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4716 }
4717 return function;
4718 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004719
4720 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004721 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004722}
4723
4724
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004725RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004726 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004727
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004728 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004729 Handle<Object> object = args.at<Object>(0);
4730 if (object->IsJSObject()) {
4731 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004732 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004733 MaybeObject* ok = js_object->TransformToFastProperties(0);
4734 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004735 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004736 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004737 return *object;
4738}
4739
4740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004741RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004742 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004743
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004744 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004745 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004746 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004747 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004748 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004749 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004750 return *object;
4751}
4752
4753
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004754RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004755 NoHandleAllocation ha;
4756 ASSERT(args.length() == 1);
4757
4758 return args[0]->ToBoolean();
4759}
4760
4761
4762// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4763// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004764RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004765 NoHandleAllocation ha;
4766
4767 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004768 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004769 HeapObject* heap_obj = HeapObject::cast(obj);
4770
4771 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004772 if (heap_obj->map()->is_undetectable()) {
4773 return isolate->heap()->undefined_symbol();
4774 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004775
4776 InstanceType instance_type = heap_obj->map()->instance_type();
4777 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004778 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004779 }
4780
4781 switch (instance_type) {
4782 case ODDBALL_TYPE:
4783 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004784 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004785 }
4786 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004787 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004788 }
4789 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004790 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004791 case JS_FUNCTION_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004792 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004793 default:
4794 // For any kind of object not handled above, the spec rule for
4795 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004796 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004797 }
4798}
4799
4800
lrn@chromium.org25156de2010-04-06 13:10:27 +00004801static bool AreDigits(const char*s, int from, int to) {
4802 for (int i = from; i < to; i++) {
4803 if (s[i] < '0' || s[i] > '9') return false;
4804 }
4805
4806 return true;
4807}
4808
4809
4810static int ParseDecimalInteger(const char*s, int from, int to) {
4811 ASSERT(to - from < 10); // Overflow is not possible.
4812 ASSERT(from < to);
4813 int d = s[from] - '0';
4814
4815 for (int i = from + 1; i < to; i++) {
4816 d = 10 * d + (s[i] - '0');
4817 }
4818
4819 return d;
4820}
4821
4822
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004823RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004824 NoHandleAllocation ha;
4825 ASSERT(args.length() == 1);
4826 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004827 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004828
4829 // Fast case: short integer or some sorts of junk values.
4830 int len = subject->length();
4831 if (subject->IsSeqAsciiString()) {
4832 if (len == 0) return Smi::FromInt(0);
4833
4834 char const* data = SeqAsciiString::cast(subject)->GetChars();
4835 bool minus = (data[0] == '-');
4836 int start_pos = (minus ? 1 : 0);
4837
4838 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004839 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004840 } else if (data[start_pos] > '9') {
4841 // Fast check for a junk value. A valid string may start from a
4842 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4843 // the 'I' character ('Infinity'). All of that have codes not greater than
4844 // '9' except 'I'.
4845 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004846 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004847 }
4848 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4849 // The maximal/minimal smi has 10 digits. If the string has less digits we
4850 // know it will fit into the smi-data type.
4851 int d = ParseDecimalInteger(data, start_pos, len);
4852 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004853 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004854 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004855 } else if (!subject->HasHashCode() &&
4856 len <= String::kMaxArrayIndexSize &&
4857 (len == 1 || data[0] != '0')) {
4858 // String hash is not calculated yet but all the data are present.
4859 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004860 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004861#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004862 subject->Hash(); // Force hash calculation.
4863 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4864 static_cast<int>(hash));
4865#endif
4866 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004867 }
4868 return Smi::FromInt(d);
4869 }
4870 }
4871
4872 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004873 return isolate->heap()->NumberFromDouble(
4874 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004875}
4876
4877
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004878RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004879 NoHandleAllocation ha;
4880 ASSERT(args.length() == 1);
4881
4882 CONVERT_CHECKED(JSArray, codes, args[0]);
4883 int length = Smi::cast(codes->length())->value();
4884
4885 // Check if the string can be ASCII.
4886 int i;
4887 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004888 Object* element;
4889 { MaybeObject* maybe_element = codes->GetElement(i);
4890 // We probably can't get an exception here, but just in order to enforce
4891 // the checking of inputs in the runtime calls we check here.
4892 if (!maybe_element->ToObject(&element)) return maybe_element;
4893 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004894 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4895 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4896 break;
4897 }
4898
lrn@chromium.org303ada72010-10-27 09:33:13 +00004899 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004900 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004901 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004902 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004903 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004904 }
4905
lrn@chromium.org303ada72010-10-27 09:33:13 +00004906 Object* object = NULL;
4907 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004908 String* result = String::cast(object);
4909 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004910 Object* element;
4911 { MaybeObject* maybe_element = codes->GetElement(i);
4912 if (!maybe_element->ToObject(&element)) return maybe_element;
4913 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004914 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004915 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004916 }
4917 return result;
4918}
4919
4920
4921// kNotEscaped is generated by the following:
4922//
4923// #!/bin/perl
4924// for (my $i = 0; $i < 256; $i++) {
4925// print "\n" if $i % 16 == 0;
4926// my $c = chr($i);
4927// my $escaped = 1;
4928// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4929// print $escaped ? "0, " : "1, ";
4930// }
4931
4932
4933static bool IsNotEscaped(uint16_t character) {
4934 // Only for 8 bit characters, the rest are always escaped (in a different way)
4935 ASSERT(character < 256);
4936 static const char kNotEscaped[256] = {
4937 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4938 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4939 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4940 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4941 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4942 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4943 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4944 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4945 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4946 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4947 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4948 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4949 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4950 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4951 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4952 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4953 };
4954 return kNotEscaped[character] != 0;
4955}
4956
4957
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004958RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004959 const char hex_chars[] = "0123456789ABCDEF";
4960 NoHandleAllocation ha;
4961 ASSERT(args.length() == 1);
4962 CONVERT_CHECKED(String, source, args[0]);
4963
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004964 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004965
4966 int escaped_length = 0;
4967 int length = source->length();
4968 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004969 Access<StringInputBuffer> buffer(
4970 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004971 buffer->Reset(source);
4972 while (buffer->has_more()) {
4973 uint16_t character = buffer->GetNext();
4974 if (character >= 256) {
4975 escaped_length += 6;
4976 } else if (IsNotEscaped(character)) {
4977 escaped_length++;
4978 } else {
4979 escaped_length += 3;
4980 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004981 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004982 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004983 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004984 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004985 return Failure::OutOfMemoryException();
4986 }
4987 }
4988 }
4989 // No length change implies no change. Return original string if no change.
4990 if (escaped_length == length) {
4991 return source;
4992 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004993 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004994 { MaybeObject* maybe_o =
4995 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004996 if (!maybe_o->ToObject(&o)) return maybe_o;
4997 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004998 String* destination = String::cast(o);
4999 int dest_position = 0;
5000
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005001 Access<StringInputBuffer> buffer(
5002 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005003 buffer->Rewind();
5004 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005005 uint16_t chr = buffer->GetNext();
5006 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005007 destination->Set(dest_position, '%');
5008 destination->Set(dest_position+1, 'u');
5009 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5010 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5011 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5012 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005013 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005014 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005015 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005016 dest_position++;
5017 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005018 destination->Set(dest_position, '%');
5019 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5020 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005021 dest_position += 3;
5022 }
5023 }
5024 return destination;
5025}
5026
5027
5028static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5029 static const signed char kHexValue['g'] = {
5030 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5031 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5032 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5033 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5034 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5035 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5036 -1, 10, 11, 12, 13, 14, 15 };
5037
5038 if (character1 > 'f') return -1;
5039 int hi = kHexValue[character1];
5040 if (hi == -1) return -1;
5041 if (character2 > 'f') return -1;
5042 int lo = kHexValue[character2];
5043 if (lo == -1) return -1;
5044 return (hi << 4) + lo;
5045}
5046
5047
ager@chromium.org870a0b62008-11-04 11:43:05 +00005048static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005049 int i,
5050 int length,
5051 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005052 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005053 int32_t hi = 0;
5054 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005055 if (character == '%' &&
5056 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005057 source->Get(i + 1) == 'u' &&
5058 (hi = TwoDigitHex(source->Get(i + 2),
5059 source->Get(i + 3))) != -1 &&
5060 (lo = TwoDigitHex(source->Get(i + 4),
5061 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005062 *step = 6;
5063 return (hi << 8) + lo;
5064 } else if (character == '%' &&
5065 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005066 (lo = TwoDigitHex(source->Get(i + 1),
5067 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005068 *step = 3;
5069 return lo;
5070 } else {
5071 *step = 1;
5072 return character;
5073 }
5074}
5075
5076
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005077RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005078 NoHandleAllocation ha;
5079 ASSERT(args.length() == 1);
5080 CONVERT_CHECKED(String, source, args[0]);
5081
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005082 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005083
5084 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005085 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005086
5087 int unescaped_length = 0;
5088 for (int i = 0; i < length; unescaped_length++) {
5089 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005090 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005091 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005092 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005093 i += step;
5094 }
5095
5096 // No length change implies no change. Return original string if no change.
5097 if (unescaped_length == length)
5098 return source;
5099
lrn@chromium.org303ada72010-10-27 09:33:13 +00005100 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005101 { MaybeObject* maybe_o =
5102 ascii ?
5103 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5104 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005105 if (!maybe_o->ToObject(&o)) return maybe_o;
5106 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005107 String* destination = String::cast(o);
5108
5109 int dest_position = 0;
5110 for (int i = 0; i < length; dest_position++) {
5111 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005112 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005113 i += step;
5114 }
5115 return destination;
5116}
5117
5118
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005119static const unsigned int kQuoteTableLength = 128u;
5120
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005121static const int kJsonQuotesCharactersPerEntry = 8;
5122static const char* const JsonQuotes =
5123 "\\u0000 \\u0001 \\u0002 \\u0003 "
5124 "\\u0004 \\u0005 \\u0006 \\u0007 "
5125 "\\b \\t \\n \\u000b "
5126 "\\f \\r \\u000e \\u000f "
5127 "\\u0010 \\u0011 \\u0012 \\u0013 "
5128 "\\u0014 \\u0015 \\u0016 \\u0017 "
5129 "\\u0018 \\u0019 \\u001a \\u001b "
5130 "\\u001c \\u001d \\u001e \\u001f "
5131 " ! \\\" # "
5132 "$ % & ' "
5133 "( ) * + "
5134 ", - . / "
5135 "0 1 2 3 "
5136 "4 5 6 7 "
5137 "8 9 : ; "
5138 "< = > ? "
5139 "@ A B C "
5140 "D E F G "
5141 "H I J K "
5142 "L M N O "
5143 "P Q R S "
5144 "T U V W "
5145 "X Y Z [ "
5146 "\\\\ ] ^ _ "
5147 "` a b c "
5148 "d e f g "
5149 "h i j k "
5150 "l m n o "
5151 "p q r s "
5152 "t u v w "
5153 "x y z { "
5154 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005155
5156
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005157// For a string that is less than 32k characters it should always be
5158// possible to allocate it in new space.
5159static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5160
5161
5162// Doing JSON quoting cannot make the string more than this many times larger.
5163static const int kJsonQuoteWorstCaseBlowup = 6;
5164
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005165static const int kSpaceForQuotesAndComma = 3;
5166static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005167
5168// Covers the entire ASCII range (all other characters are unchanged by JSON
5169// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005170static const byte JsonQuoteLengths[kQuoteTableLength] = {
5171 6, 6, 6, 6, 6, 6, 6, 6,
5172 2, 2, 2, 6, 2, 2, 6, 6,
5173 6, 6, 6, 6, 6, 6, 6, 6,
5174 6, 6, 6, 6, 6, 6, 6, 6,
5175 1, 1, 2, 1, 1, 1, 1, 1,
5176 1, 1, 1, 1, 1, 1, 1, 1,
5177 1, 1, 1, 1, 1, 1, 1, 1,
5178 1, 1, 1, 1, 1, 1, 1, 1,
5179 1, 1, 1, 1, 1, 1, 1, 1,
5180 1, 1, 1, 1, 1, 1, 1, 1,
5181 1, 1, 1, 1, 1, 1, 1, 1,
5182 1, 1, 1, 1, 2, 1, 1, 1,
5183 1, 1, 1, 1, 1, 1, 1, 1,
5184 1, 1, 1, 1, 1, 1, 1, 1,
5185 1, 1, 1, 1, 1, 1, 1, 1,
5186 1, 1, 1, 1, 1, 1, 1, 1,
5187};
5188
5189
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005190template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005191MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005192
5193
5194template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005195MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5196 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005197}
5198
5199
5200template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005201MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5202 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005203}
5204
5205
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005206template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005207static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5208 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005209 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005210 const Char* read_cursor = characters.start();
5211 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005212 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005213 int quoted_length = kSpaceForQuotes;
5214 while (read_cursor < end) {
5215 Char c = *(read_cursor++);
5216 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5217 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005218 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005219 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005220 }
5221 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005222 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5223 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005224 Object* new_object;
5225 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005226 return new_alloc;
5227 }
5228 StringType* new_string = StringType::cast(new_object);
5229
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005230 Char* write_cursor = reinterpret_cast<Char*>(
5231 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005232 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005233 *(write_cursor++) = '"';
5234
5235 read_cursor = characters.start();
5236 while (read_cursor < end) {
5237 Char c = *(read_cursor++);
5238 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5239 *(write_cursor++) = c;
5240 } else {
5241 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5242 const char* replacement = JsonQuotes +
5243 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5244 for (int i = 0; i < len; i++) {
5245 *write_cursor++ = *replacement++;
5246 }
5247 }
5248 }
5249 *(write_cursor++) = '"';
5250 return new_string;
5251}
5252
5253
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005254template <typename SinkChar, typename SourceChar>
5255static inline SinkChar* WriteQuoteJsonString(
5256 Isolate* isolate,
5257 SinkChar* write_cursor,
5258 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005259 // SinkChar is only char if SourceChar is guaranteed to be char.
5260 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005261 const SourceChar* read_cursor = characters.start();
5262 const SourceChar* end = read_cursor + characters.length();
5263 *(write_cursor++) = '"';
5264 while (read_cursor < end) {
5265 SourceChar c = *(read_cursor++);
5266 if (sizeof(SourceChar) > 1u &&
5267 static_cast<unsigned>(c) >= kQuoteTableLength) {
5268 *(write_cursor++) = static_cast<SinkChar>(c);
5269 } else {
5270 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5271 const char* replacement = JsonQuotes +
5272 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5273 write_cursor[0] = replacement[0];
5274 if (len > 1) {
5275 write_cursor[1] = replacement[1];
5276 if (len > 2) {
5277 ASSERT(len == 6);
5278 write_cursor[2] = replacement[2];
5279 write_cursor[3] = replacement[3];
5280 write_cursor[4] = replacement[4];
5281 write_cursor[5] = replacement[5];
5282 }
5283 }
5284 write_cursor += len;
5285 }
5286 }
5287 *(write_cursor++) = '"';
5288 return write_cursor;
5289}
5290
5291
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005292template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005293static MaybeObject* QuoteJsonString(Isolate* isolate,
5294 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005295 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005296 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005297 int worst_case_length =
5298 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005299 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005300 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005301 }
5302
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005303 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5304 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005305 Object* new_object;
5306 if (!new_alloc->ToObject(&new_object)) {
5307 return new_alloc;
5308 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005309 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005310 // Even if our string is small enough to fit in new space we still have to
5311 // handle it being allocated in old space as may happen in the third
5312 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5313 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005314 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005315 }
5316 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005317 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005318
5319 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5320 Char* write_cursor = reinterpret_cast<Char*>(
5321 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005322 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005323 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5324 write_cursor,
5325 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005326 int final_length = static_cast<int>(
5327 write_cursor - reinterpret_cast<Char*>(
5328 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005329 isolate->heap()->new_space()->
5330 template ShrinkStringAtAllocationBoundary<StringType>(
5331 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005332 return new_string;
5333}
5334
5335
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005336RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005337 NoHandleAllocation ha;
5338 CONVERT_CHECKED(String, str, args[0]);
5339 if (!str->IsFlat()) {
5340 MaybeObject* try_flatten = str->TryFlatten();
5341 Object* flat;
5342 if (!try_flatten->ToObject(&flat)) {
5343 return try_flatten;
5344 }
5345 str = String::cast(flat);
5346 ASSERT(str->IsFlat());
5347 }
5348 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005349 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5350 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005351 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005352 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5353 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005354 }
5355}
5356
5357
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005358RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005359 NoHandleAllocation ha;
5360 CONVERT_CHECKED(String, str, args[0]);
5361 if (!str->IsFlat()) {
5362 MaybeObject* try_flatten = str->TryFlatten();
5363 Object* flat;
5364 if (!try_flatten->ToObject(&flat)) {
5365 return try_flatten;
5366 }
5367 str = String::cast(flat);
5368 ASSERT(str->IsFlat());
5369 }
5370 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005371 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5372 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005373 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005374 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5375 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005376 }
5377}
5378
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005379
5380template <typename Char, typename StringType>
5381static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5382 FixedArray* array,
5383 int worst_case_length) {
5384 int length = array->length();
5385
5386 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5387 worst_case_length);
5388 Object* new_object;
5389 if (!new_alloc->ToObject(&new_object)) {
5390 return new_alloc;
5391 }
5392 if (!isolate->heap()->new_space()->Contains(new_object)) {
5393 // Even if our string is small enough to fit in new space we still have to
5394 // handle it being allocated in old space as may happen in the third
5395 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5396 // CEntryStub::GenerateCore.
5397 return isolate->heap()->undefined_value();
5398 }
5399 AssertNoAllocation no_gc;
5400 StringType* new_string = StringType::cast(new_object);
5401 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5402
5403 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5404 Char* write_cursor = reinterpret_cast<Char*>(
5405 new_string->address() + SeqAsciiString::kHeaderSize);
5406 *(write_cursor++) = '[';
5407 for (int i = 0; i < length; i++) {
5408 if (i != 0) *(write_cursor++) = ',';
5409 String* str = String::cast(array->get(i));
5410 if (str->IsTwoByteRepresentation()) {
5411 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5412 write_cursor,
5413 str->ToUC16Vector());
5414 } else {
5415 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5416 write_cursor,
5417 str->ToAsciiVector());
5418 }
5419 }
5420 *(write_cursor++) = ']';
5421
5422 int final_length = static_cast<int>(
5423 write_cursor - reinterpret_cast<Char*>(
5424 new_string->address() + SeqAsciiString::kHeaderSize));
5425 isolate->heap()->new_space()->
5426 template ShrinkStringAtAllocationBoundary<StringType>(
5427 new_string, final_length);
5428 return new_string;
5429}
5430
5431
5432RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5433 NoHandleAllocation ha;
5434 ASSERT(args.length() == 1);
5435 CONVERT_CHECKED(JSArray, array, args[0]);
5436
5437 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5438 FixedArray* elements = FixedArray::cast(array->elements());
5439 int n = elements->length();
5440 bool ascii = true;
5441 int total_length = 0;
5442
5443 for (int i = 0; i < n; i++) {
5444 Object* elt = elements->get(i);
5445 if (!elt->IsString()) return isolate->heap()->undefined_value();
5446 String* element = String::cast(elt);
5447 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5448 total_length += element->length();
5449 if (ascii && element->IsTwoByteRepresentation()) {
5450 ascii = false;
5451 }
5452 }
5453
5454 int worst_case_length =
5455 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5456 + total_length * kJsonQuoteWorstCaseBlowup;
5457
5458 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5459 return isolate->heap()->undefined_value();
5460 }
5461
5462 if (ascii) {
5463 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5464 elements,
5465 worst_case_length);
5466 } else {
5467 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5468 elements,
5469 worst_case_length);
5470 }
5471}
5472
5473
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005474RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005475 NoHandleAllocation ha;
5476
5477 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005478 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005479
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005480 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005481
lrn@chromium.org25156de2010-04-06 13:10:27 +00005482 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005483 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005484 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005485}
5486
5487
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005488RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005489 NoHandleAllocation ha;
5490 CONVERT_CHECKED(String, str, args[0]);
5491
5492 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005493 double value = StringToDouble(isolate->unicode_cache(),
5494 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005495
5496 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005497 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005498}
5499
5500
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005501template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005502MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005503 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005504 String* s,
5505 int length,
5506 int input_string_length,
5507 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005508 // We try this twice, once with the assumption that the result is no longer
5509 // than the input and, if that assumption breaks, again with the exact
5510 // length. This may not be pretty, but it is nicer than what was here before
5511 // and I hereby claim my vaffel-is.
5512 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005513 // Allocate the resulting string.
5514 //
5515 // NOTE: This assumes that the upper/lower case of an ascii
5516 // character is also ascii. This is currently the case, but it
5517 // might break in the future if we implement more context and locale
5518 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005519 Object* o;
5520 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005521 ? isolate->heap()->AllocateRawAsciiString(length)
5522 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005523 if (!maybe_o->ToObject(&o)) return maybe_o;
5524 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005525 String* result = String::cast(o);
5526 bool has_changed_character = false;
5527
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005528 // Convert all characters to upper case, assuming that they will fit
5529 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005530 Access<StringInputBuffer> buffer(
5531 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005532 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005533 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005534 // We can assume that the string is not empty
5535 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005536 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005537 bool has_next = buffer->has_more();
5538 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005539 int char_length = mapping->get(current, next, chars);
5540 if (char_length == 0) {
5541 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005542 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005543 i++;
5544 } else if (char_length == 1) {
5545 // Common case: converting the letter resulted in one character.
5546 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005547 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005548 has_changed_character = true;
5549 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005550 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005551 // We've assumed that the result would be as long as the
5552 // input but here is a character that converts to several
5553 // characters. No matter, we calculate the exact length
5554 // of the result and try the whole thing again.
5555 //
5556 // Note that this leaves room for optimization. We could just
5557 // memcpy what we already have to the result string. Also,
5558 // the result string is the last object allocated we could
5559 // "realloc" it and probably, in the vast majority of cases,
5560 // extend the existing string to be able to hold the full
5561 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005562 int next_length = 0;
5563 if (has_next) {
5564 next_length = mapping->get(next, 0, chars);
5565 if (next_length == 0) next_length = 1;
5566 }
5567 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005568 while (buffer->has_more()) {
5569 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005570 // NOTE: we use 0 as the next character here because, while
5571 // the next character may affect what a character converts to,
5572 // it does not in any case affect the length of what it convert
5573 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005574 int char_length = mapping->get(current, 0, chars);
5575 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005576 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005577 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005578 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005579 return Failure::OutOfMemoryException();
5580 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005581 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005582 // Try again with the real length.
5583 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005584 } else {
5585 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005586 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005587 i++;
5588 }
5589 has_changed_character = true;
5590 }
5591 current = next;
5592 }
5593 if (has_changed_character) {
5594 return result;
5595 } else {
5596 // If we didn't actually change anything in doing the conversion
5597 // we simple return the result and let the converted string
5598 // become garbage; there is no reason to keep two identical strings
5599 // alive.
5600 return s;
5601 }
5602}
5603
5604
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005605namespace {
5606
lrn@chromium.org303ada72010-10-27 09:33:13 +00005607static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5608
5609
5610// Given a word and two range boundaries returns a word with high bit
5611// set in every byte iff the corresponding input byte was strictly in
5612// the range (m, n). All the other bits in the result are cleared.
5613// This function is only useful when it can be inlined and the
5614// boundaries are statically known.
5615// Requires: all bytes in the input word and the boundaries must be
5616// ascii (less than 0x7F).
5617static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5618 // Every byte in an ascii string is less than or equal to 0x7F.
5619 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5620 // Use strict inequalities since in edge cases the function could be
5621 // further simplified.
5622 ASSERT(0 < m && m < n && n < 0x7F);
5623 // Has high bit set in every w byte less than n.
5624 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5625 // Has high bit set in every w byte greater than m.
5626 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5627 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5628}
5629
5630
5631enum AsciiCaseConversion {
5632 ASCII_TO_LOWER,
5633 ASCII_TO_UPPER
5634};
5635
5636
5637template <AsciiCaseConversion dir>
5638struct FastAsciiConverter {
5639 static bool Convert(char* dst, char* src, int length) {
5640#ifdef DEBUG
5641 char* saved_dst = dst;
5642 char* saved_src = src;
5643#endif
5644 // We rely on the distance between upper and lower case letters
5645 // being a known power of 2.
5646 ASSERT('a' - 'A' == (1 << 5));
5647 // Boundaries for the range of input characters than require conversion.
5648 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5649 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5650 bool changed = false;
5651 char* const limit = src + length;
5652#ifdef V8_HOST_CAN_READ_UNALIGNED
5653 // Process the prefix of the input that requires no conversion one
5654 // (machine) word at a time.
5655 while (src <= limit - sizeof(uintptr_t)) {
5656 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5657 if (AsciiRangeMask(w, lo, hi) != 0) {
5658 changed = true;
5659 break;
5660 }
5661 *reinterpret_cast<uintptr_t*>(dst) = w;
5662 src += sizeof(uintptr_t);
5663 dst += sizeof(uintptr_t);
5664 }
5665 // Process the remainder of the input performing conversion when
5666 // required one word at a time.
5667 while (src <= limit - sizeof(uintptr_t)) {
5668 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5669 uintptr_t m = AsciiRangeMask(w, lo, hi);
5670 // The mask has high (7th) bit set in every byte that needs
5671 // conversion and we know that the distance between cases is
5672 // 1 << 5.
5673 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5674 src += sizeof(uintptr_t);
5675 dst += sizeof(uintptr_t);
5676 }
5677#endif
5678 // Process the last few bytes of the input (or the whole input if
5679 // unaligned access is not supported).
5680 while (src < limit) {
5681 char c = *src;
5682 if (lo < c && c < hi) {
5683 c ^= (1 << 5);
5684 changed = true;
5685 }
5686 *dst = c;
5687 ++src;
5688 ++dst;
5689 }
5690#ifdef DEBUG
5691 CheckConvert(saved_dst, saved_src, length, changed);
5692#endif
5693 return changed;
5694 }
5695
5696#ifdef DEBUG
5697 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5698 bool expected_changed = false;
5699 for (int i = 0; i < length; i++) {
5700 if (dst[i] == src[i]) continue;
5701 expected_changed = true;
5702 if (dir == ASCII_TO_LOWER) {
5703 ASSERT('A' <= src[i] && src[i] <= 'Z');
5704 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5705 } else {
5706 ASSERT(dir == ASCII_TO_UPPER);
5707 ASSERT('a' <= src[i] && src[i] <= 'z');
5708 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5709 }
5710 }
5711 ASSERT(expected_changed == changed);
5712 }
5713#endif
5714};
5715
5716
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005717struct ToLowerTraits {
5718 typedef unibrow::ToLowercase UnibrowConverter;
5719
lrn@chromium.org303ada72010-10-27 09:33:13 +00005720 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005721};
5722
5723
5724struct ToUpperTraits {
5725 typedef unibrow::ToUppercase UnibrowConverter;
5726
lrn@chromium.org303ada72010-10-27 09:33:13 +00005727 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005728};
5729
5730} // namespace
5731
5732
5733template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005734MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005735 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005736 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005737 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005738 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005739 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005740 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005741
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005742 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005743 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005744 if (length == 0) return s;
5745
5746 // Simpler handling of ascii strings.
5747 //
5748 // NOTE: This assumes that the upper/lower case of an ascii
5749 // character is also ascii. This is currently the case, but it
5750 // might break in the future if we implement more context and locale
5751 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005752 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005753 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005754 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005755 if (!maybe_o->ToObject(&o)) return maybe_o;
5756 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005757 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005758 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005759 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005760 return has_changed_character ? result : s;
5761 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005762
lrn@chromium.org303ada72010-10-27 09:33:13 +00005763 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005764 { MaybeObject* maybe_answer =
5765 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005766 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5767 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005768 if (answer->IsSmi()) {
5769 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005770 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005771 ConvertCaseHelper(isolate,
5772 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005773 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5774 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005775 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005776 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005777}
5778
5779
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005780RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005781 return ConvertCase<ToLowerTraits>(
5782 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005783}
5784
5785
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005786RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005787 return ConvertCase<ToUpperTraits>(
5788 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005789}
5790
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005791
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005792static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5793 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5794}
5795
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005796
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005797RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005798 NoHandleAllocation ha;
5799 ASSERT(args.length() == 3);
5800
5801 CONVERT_CHECKED(String, s, args[0]);
5802 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5803 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5804
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005805 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005806 int length = s->length();
5807
5808 int left = 0;
5809 if (trimLeft) {
5810 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5811 left++;
5812 }
5813 }
5814
5815 int right = length;
5816 if (trimRight) {
5817 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5818 right--;
5819 }
5820 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005821 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005822}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005823
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005824
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005825void FindAsciiStringIndices(Vector<const char> subject,
5826 char pattern,
5827 ZoneList<int>* indices,
5828 unsigned int limit) {
5829 ASSERT(limit > 0);
5830 // Collect indices of pattern in subject using memchr.
5831 // Stop after finding at most limit values.
5832 const char* subject_start = reinterpret_cast<const char*>(subject.start());
5833 const char* subject_end = subject_start + subject.length();
5834 const char* pos = subject_start;
5835 while (limit > 0) {
5836 pos = reinterpret_cast<const char*>(
5837 memchr(pos, pattern, subject_end - pos));
5838 if (pos == NULL) return;
5839 indices->Add(static_cast<int>(pos - subject_start));
5840 pos++;
5841 limit--;
5842 }
5843}
5844
5845
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005846template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005847void FindStringIndices(Isolate* isolate,
5848 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005849 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005850 ZoneList<int>* indices,
5851 unsigned int limit) {
5852 ASSERT(limit > 0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005853 // Collect indices of pattern in subject.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005854 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005855 int pattern_length = pattern.length();
5856 int index = 0;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005857 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005858 while (limit > 0) {
5859 index = search.Search(subject, index);
5860 if (index < 0) return;
5861 indices->Add(index);
5862 index += pattern_length;
5863 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005864 }
5865}
5866
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005867
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005868RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005869 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005870 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005871 CONVERT_ARG_CHECKED(String, subject, 0);
5872 CONVERT_ARG_CHECKED(String, pattern, 1);
5873 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5874
5875 int subject_length = subject->length();
5876 int pattern_length = pattern->length();
5877 RUNTIME_ASSERT(pattern_length > 0);
5878
5879 // The limit can be very large (0xffffffffu), but since the pattern
5880 // isn't empty, we can never create more parts than ~half the length
5881 // of the subject.
5882
5883 if (!subject->IsFlat()) FlattenString(subject);
5884
5885 static const int kMaxInitialListCapacity = 16;
5886
danno@chromium.org40cb8782011-05-25 07:58:50 +00005887 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005888
5889 // Find (up to limit) indices of separator and end-of-string in subject
5890 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5891 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005892 if (!pattern->IsFlat()) FlattenString(pattern);
5893
5894 // No allocation block.
5895 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005896 AssertNoAllocation nogc;
5897 if (subject->IsAsciiRepresentation()) {
5898 Vector<const char> subject_vector = subject->ToAsciiVector();
5899 if (pattern->IsAsciiRepresentation()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005900 Vector<const char> pattern_vector = pattern->ToAsciiVector();
5901 if (pattern_vector.length() == 1) {
5902 FindAsciiStringIndices(subject_vector,
5903 pattern_vector[0],
5904 &indices,
5905 limit);
5906 } else {
5907 FindStringIndices(isolate,
5908 subject_vector,
5909 pattern_vector,
5910 &indices,
5911 limit);
5912 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005913 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005914 FindStringIndices(isolate,
5915 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005916 pattern->ToUC16Vector(),
5917 &indices,
5918 limit);
5919 }
5920 } else {
5921 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5922 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005923 FindStringIndices(isolate,
5924 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005925 pattern->ToAsciiVector(),
5926 &indices,
5927 limit);
5928 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005929 FindStringIndices(isolate,
5930 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005931 pattern->ToUC16Vector(),
5932 &indices,
5933 limit);
5934 }
5935 }
5936 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005937
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005938 if (static_cast<uint32_t>(indices.length()) < limit) {
5939 indices.Add(subject_length);
5940 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005941
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005942 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005943
5944 // Create JSArray of substrings separated by separator.
5945 int part_count = indices.length();
5946
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005947 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005948 result->set_length(Smi::FromInt(part_count));
5949
5950 ASSERT(result->HasFastElements());
5951
5952 if (part_count == 1 && indices.at(0) == subject_length) {
5953 FixedArray::cast(result->elements())->set(0, *subject);
5954 return *result;
5955 }
5956
5957 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5958 int part_start = 0;
5959 for (int i = 0; i < part_count; i++) {
5960 HandleScope local_loop_handle;
5961 int part_end = indices.at(i);
5962 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00005963 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005964 elements->set(i, *substring);
5965 part_start = part_end + pattern_length;
5966 }
5967
5968 return *result;
5969}
5970
5971
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005972// Copies ascii characters to the given fixed array looking up
5973// one-char strings in the cache. Gives up on the first char that is
5974// not in the cache and fills the remainder with smi zeros. Returns
5975// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005976static int CopyCachedAsciiCharsToArray(Heap* heap,
5977 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005978 FixedArray* elements,
5979 int length) {
5980 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005981 FixedArray* ascii_cache = heap->single_character_string_cache();
5982 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005983 int i;
5984 for (i = 0; i < length; ++i) {
5985 Object* value = ascii_cache->get(chars[i]);
5986 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005987 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005988 elements->set(i, value, SKIP_WRITE_BARRIER);
5989 }
5990 if (i < length) {
5991 ASSERT(Smi::FromInt(0) == 0);
5992 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5993 }
5994#ifdef DEBUG
5995 for (int j = 0; j < length; ++j) {
5996 Object* element = elements->get(j);
5997 ASSERT(element == Smi::FromInt(0) ||
5998 (element->IsString() && String::cast(element)->LooksValid()));
5999 }
6000#endif
6001 return i;
6002}
6003
6004
6005// Converts a String to JSArray.
6006// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006007RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006008 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006009 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006010 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006011 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006012
6013 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006014 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006015
6016 Handle<FixedArray> elements;
6017 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006018 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006019 { MaybeObject* maybe_obj =
6020 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006021 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6022 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006023 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006024
6025 Vector<const char> chars = s->ToAsciiVector();
6026 // Note, this will initialize all elements (not only the prefix)
6027 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006028 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
6029 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006030 *elements,
6031 length);
6032
6033 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006034 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
6035 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006036 }
6037 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006038 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006039 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006040 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6041 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006042 }
6043 }
6044
6045#ifdef DEBUG
6046 for (int i = 0; i < length; ++i) {
6047 ASSERT(String::cast(elements->get(i))->length() == 1);
6048 }
6049#endif
6050
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006051 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006052}
6053
6054
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006055RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006056 NoHandleAllocation ha;
6057 ASSERT(args.length() == 1);
6058 CONVERT_CHECKED(String, value, args[0]);
6059 return value->ToObject();
6060}
6061
6062
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006063bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006064 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006065 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006066 return char_length == 0;
6067}
6068
6069
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006070RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006071 NoHandleAllocation ha;
6072 ASSERT(args.length() == 1);
6073
6074 Object* number = args[0];
6075 RUNTIME_ASSERT(number->IsNumber());
6076
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006077 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006078}
6079
6080
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006081RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006082 NoHandleAllocation ha;
6083 ASSERT(args.length() == 1);
6084
6085 Object* number = args[0];
6086 RUNTIME_ASSERT(number->IsNumber());
6087
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006088 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006089}
6090
6091
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006092RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006093 NoHandleAllocation ha;
6094 ASSERT(args.length() == 1);
6095
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006096 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006097
6098 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6099 if (number > 0 && number <= Smi::kMaxValue) {
6100 return Smi::FromInt(static_cast<int>(number));
6101 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006102 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006103}
6104
6105
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006106RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006107 NoHandleAllocation ha;
6108 ASSERT(args.length() == 1);
6109
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006110 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006111
6112 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6113 if (number > 0 && number <= Smi::kMaxValue) {
6114 return Smi::FromInt(static_cast<int>(number));
6115 }
6116
6117 double double_value = DoubleToInteger(number);
6118 // Map both -0 and +0 to +0.
6119 if (double_value == 0) double_value = 0;
6120
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006121 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006122}
6123
6124
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006125RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006126 NoHandleAllocation ha;
6127 ASSERT(args.length() == 1);
6128
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006129 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006130 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006131}
6132
6133
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006134RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006135 NoHandleAllocation ha;
6136 ASSERT(args.length() == 1);
6137
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006138 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006139
6140 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6141 if (number > 0 && number <= Smi::kMaxValue) {
6142 return Smi::FromInt(static_cast<int>(number));
6143 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006144 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006145}
6146
6147
ager@chromium.org870a0b62008-11-04 11:43:05 +00006148// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6149// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006150RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006151 NoHandleAllocation ha;
6152 ASSERT(args.length() == 1);
6153
6154 Object* obj = args[0];
6155 if (obj->IsSmi()) {
6156 return obj;
6157 }
6158 if (obj->IsHeapNumber()) {
6159 double value = HeapNumber::cast(obj)->value();
6160 int int_value = FastD2I(value);
6161 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6162 return Smi::FromInt(int_value);
6163 }
6164 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006165 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006166}
6167
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006168
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006169RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006170 NoHandleAllocation ha;
6171 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006172 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006173}
6174
6175
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006176RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006177 NoHandleAllocation ha;
6178 ASSERT(args.length() == 2);
6179
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006180 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6181 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006182 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006183}
6184
6185
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006186RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006187 NoHandleAllocation ha;
6188 ASSERT(args.length() == 2);
6189
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006190 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6191 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006192 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006193}
6194
6195
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006196RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006197 NoHandleAllocation ha;
6198 ASSERT(args.length() == 2);
6199
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006200 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6201 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006202 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006203}
6204
6205
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006206RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006207 NoHandleAllocation ha;
6208 ASSERT(args.length() == 1);
6209
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006210 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006211 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006212}
6213
6214
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006215RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006216 NoHandleAllocation ha;
6217 ASSERT(args.length() == 0);
6218
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006219 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006220}
6221
6222
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006223RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006224 NoHandleAllocation ha;
6225 ASSERT(args.length() == 2);
6226
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006227 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6228 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006229 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006230}
6231
6232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006233RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006234 NoHandleAllocation ha;
6235 ASSERT(args.length() == 2);
6236
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006237 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6238 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006239
ager@chromium.org3811b432009-10-28 14:53:37 +00006240 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006241 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006242 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006243}
6244
6245
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006246RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006247 NoHandleAllocation ha;
6248 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006249 CONVERT_CHECKED(String, str1, args[0]);
6250 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006251 isolate->counters()->string_add_runtime()->Increment();
6252 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006253}
6254
6255
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006256template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006257static inline void StringBuilderConcatHelper(String* special,
6258 sinkchar* sink,
6259 FixedArray* fixed_array,
6260 int array_length) {
6261 int position = 0;
6262 for (int i = 0; i < array_length; i++) {
6263 Object* element = fixed_array->get(i);
6264 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006265 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006266 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006267 int pos;
6268 int len;
6269 if (encoded_slice > 0) {
6270 // Position and length encoded in one smi.
6271 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6272 len = StringBuilderSubstringLength::decode(encoded_slice);
6273 } else {
6274 // Position and length encoded in two smis.
6275 Object* obj = fixed_array->get(++i);
6276 ASSERT(obj->IsSmi());
6277 pos = Smi::cast(obj)->value();
6278 len = -encoded_slice;
6279 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006280 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006281 sink + position,
6282 pos,
6283 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006284 position += len;
6285 } else {
6286 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006287 int element_length = string->length();
6288 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006289 position += element_length;
6290 }
6291 }
6292}
6293
6294
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006295RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006296 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006297 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006298 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006299 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006300 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006301 return Failure::OutOfMemoryException();
6302 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006303 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006304 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006305
6306 // This assumption is used by the slice encoding in one or two smis.
6307 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6308
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006309 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006310 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006311 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006312 }
6313 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006314 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006315 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006316 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006317
6318 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006319 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006320 } else if (array_length == 1) {
6321 Object* first = fixed_array->get(0);
6322 if (first->IsString()) return first;
6323 }
6324
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006325 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006326 int position = 0;
6327 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006328 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006329 Object* elt = fixed_array->get(i);
6330 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006331 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006332 int smi_value = Smi::cast(elt)->value();
6333 int pos;
6334 int len;
6335 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006336 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006337 pos = StringBuilderSubstringPosition::decode(smi_value);
6338 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006339 } else {
6340 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006341 len = -smi_value;
6342 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006343 i++;
6344 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006345 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006346 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006347 Object* next_smi = fixed_array->get(i);
6348 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006349 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006350 }
6351 pos = Smi::cast(next_smi)->value();
6352 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006353 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006354 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006355 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006356 ASSERT(pos >= 0);
6357 ASSERT(len >= 0);
6358 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006359 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006360 }
6361 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006362 } else if (elt->IsString()) {
6363 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006364 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006365 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006366 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006367 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006368 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006369 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006370 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006371 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006372 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006373 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006374 return Failure::OutOfMemoryException();
6375 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006376 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006377 }
6378
6379 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006380 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006381
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006382 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006383 { MaybeObject* maybe_object =
6384 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006385 if (!maybe_object->ToObject(&object)) return maybe_object;
6386 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006387 SeqAsciiString* answer = SeqAsciiString::cast(object);
6388 StringBuilderConcatHelper(special,
6389 answer->GetChars(),
6390 fixed_array,
6391 array_length);
6392 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006393 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006394 { MaybeObject* maybe_object =
6395 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006396 if (!maybe_object->ToObject(&object)) return maybe_object;
6397 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006398 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6399 StringBuilderConcatHelper(special,
6400 answer->GetChars(),
6401 fixed_array,
6402 array_length);
6403 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006404 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006405}
6406
6407
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006408RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006409 NoHandleAllocation ha;
6410 ASSERT(args.length() == 3);
6411 CONVERT_CHECKED(JSArray, array, args[0]);
6412 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006413 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006414 return Failure::OutOfMemoryException();
6415 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006416 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006417 CONVERT_CHECKED(String, separator, args[2]);
6418
6419 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006420 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006421 }
6422 FixedArray* fixed_array = FixedArray::cast(array->elements());
6423 if (fixed_array->length() < array_length) {
6424 array_length = fixed_array->length();
6425 }
6426
6427 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006428 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006429 } else if (array_length == 1) {
6430 Object* first = fixed_array->get(0);
6431 if (first->IsString()) return first;
6432 }
6433
6434 int separator_length = separator->length();
6435 int max_nof_separators =
6436 (String::kMaxLength + separator_length - 1) / separator_length;
6437 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006438 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006439 return Failure::OutOfMemoryException();
6440 }
6441 int length = (array_length - 1) * separator_length;
6442 for (int i = 0; i < array_length; i++) {
6443 Object* element_obj = fixed_array->get(i);
6444 if (!element_obj->IsString()) {
6445 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006446 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006447 }
6448 String* element = String::cast(element_obj);
6449 int increment = element->length();
6450 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006451 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006452 return Failure::OutOfMemoryException();
6453 }
6454 length += increment;
6455 }
6456
6457 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006458 { MaybeObject* maybe_object =
6459 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006460 if (!maybe_object->ToObject(&object)) return maybe_object;
6461 }
6462 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6463
6464 uc16* sink = answer->GetChars();
6465#ifdef DEBUG
6466 uc16* end = sink + length;
6467#endif
6468
6469 String* first = String::cast(fixed_array->get(0));
6470 int first_length = first->length();
6471 String::WriteToFlat(first, sink, 0, first_length);
6472 sink += first_length;
6473
6474 for (int i = 1; i < array_length; i++) {
6475 ASSERT(sink + separator_length <= end);
6476 String::WriteToFlat(separator, sink, 0, separator_length);
6477 sink += separator_length;
6478
6479 String* element = String::cast(fixed_array->get(i));
6480 int element_length = element->length();
6481 ASSERT(sink + element_length <= end);
6482 String::WriteToFlat(element, sink, 0, element_length);
6483 sink += element_length;
6484 }
6485 ASSERT(sink == end);
6486
6487 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6488 return answer;
6489}
6490
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006491template <typename Char>
6492static void JoinSparseArrayWithSeparator(FixedArray* elements,
6493 int elements_length,
6494 uint32_t array_length,
6495 String* separator,
6496 Vector<Char> buffer) {
6497 int previous_separator_position = 0;
6498 int separator_length = separator->length();
6499 int cursor = 0;
6500 for (int i = 0; i < elements_length; i += 2) {
6501 int position = NumberToInt32(elements->get(i));
6502 String* string = String::cast(elements->get(i + 1));
6503 int string_length = string->length();
6504 if (string->length() > 0) {
6505 while (previous_separator_position < position) {
6506 String::WriteToFlat<Char>(separator, &buffer[cursor],
6507 0, separator_length);
6508 cursor += separator_length;
6509 previous_separator_position++;
6510 }
6511 String::WriteToFlat<Char>(string, &buffer[cursor],
6512 0, string_length);
6513 cursor += string->length();
6514 }
6515 }
6516 if (separator_length > 0) {
6517 // Array length must be representable as a signed 32-bit number,
6518 // otherwise the total string length would have been too large.
6519 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6520 int last_array_index = static_cast<int>(array_length - 1);
6521 while (previous_separator_position < last_array_index) {
6522 String::WriteToFlat<Char>(separator, &buffer[cursor],
6523 0, separator_length);
6524 cursor += separator_length;
6525 previous_separator_position++;
6526 }
6527 }
6528 ASSERT(cursor <= buffer.length());
6529}
6530
6531
6532RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6533 NoHandleAllocation ha;
6534 ASSERT(args.length() == 3);
6535 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6536 RUNTIME_ASSERT(elements_array->HasFastElements());
6537 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6538 CONVERT_CHECKED(String, separator, args[2]);
6539 // elements_array is fast-mode JSarray of alternating positions
6540 // (increasing order) and strings.
6541 // array_length is length of original array (used to add separators);
6542 // separator is string to put between elements. Assumed to be non-empty.
6543
6544 // Find total length of join result.
6545 int string_length = 0;
6546 bool is_ascii = true;
6547 int max_string_length = SeqAsciiString::kMaxLength;
6548 bool overflow = false;
6549 CONVERT_NUMBER_CHECKED(int, elements_length,
6550 Int32, elements_array->length());
6551 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6552 FixedArray* elements = FixedArray::cast(elements_array->elements());
6553 for (int i = 0; i < elements_length; i += 2) {
6554 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6555 CONVERT_CHECKED(String, string, elements->get(i + 1));
6556 int length = string->length();
6557 if (is_ascii && !string->IsAsciiRepresentation()) {
6558 is_ascii = false;
6559 max_string_length = SeqTwoByteString::kMaxLength;
6560 }
6561 if (length > max_string_length ||
6562 max_string_length - length < string_length) {
6563 overflow = true;
6564 break;
6565 }
6566 string_length += length;
6567 }
6568 int separator_length = separator->length();
6569 if (!overflow && separator_length > 0) {
6570 if (array_length <= 0x7fffffffu) {
6571 int separator_count = static_cast<int>(array_length) - 1;
6572 int remaining_length = max_string_length - string_length;
6573 if ((remaining_length / separator_length) >= separator_count) {
6574 string_length += separator_length * (array_length - 1);
6575 } else {
6576 // Not room for the separators within the maximal string length.
6577 overflow = true;
6578 }
6579 } else {
6580 // Nonempty separator and at least 2^31-1 separators necessary
6581 // means that the string is too large to create.
6582 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6583 overflow = true;
6584 }
6585 }
6586 if (overflow) {
6587 // Throw OutOfMemory exception for creating too large a string.
6588 V8::FatalProcessOutOfMemory("Array join result too large.");
6589 }
6590
6591 if (is_ascii) {
6592 MaybeObject* result_allocation =
6593 isolate->heap()->AllocateRawAsciiString(string_length);
6594 if (result_allocation->IsFailure()) return result_allocation;
6595 SeqAsciiString* result_string =
6596 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6597 JoinSparseArrayWithSeparator<char>(elements,
6598 elements_length,
6599 array_length,
6600 separator,
6601 Vector<char>(result_string->GetChars(),
6602 string_length));
6603 return result_string;
6604 } else {
6605 MaybeObject* result_allocation =
6606 isolate->heap()->AllocateRawTwoByteString(string_length);
6607 if (result_allocation->IsFailure()) return result_allocation;
6608 SeqTwoByteString* result_string =
6609 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6610 JoinSparseArrayWithSeparator<uc16>(elements,
6611 elements_length,
6612 array_length,
6613 separator,
6614 Vector<uc16>(result_string->GetChars(),
6615 string_length));
6616 return result_string;
6617 }
6618}
6619
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006620
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006621RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006622 NoHandleAllocation ha;
6623 ASSERT(args.length() == 2);
6624
6625 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6626 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006627 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006628}
6629
6630
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006631RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006632 NoHandleAllocation ha;
6633 ASSERT(args.length() == 2);
6634
6635 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6636 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006637 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006638}
6639
6640
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006641RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006642 NoHandleAllocation ha;
6643 ASSERT(args.length() == 2);
6644
6645 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6646 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006647 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006648}
6649
6650
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006651RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006652 NoHandleAllocation ha;
6653 ASSERT(args.length() == 1);
6654
6655 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006656 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006657}
6658
6659
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006660RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006661 NoHandleAllocation ha;
6662 ASSERT(args.length() == 2);
6663
6664 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6665 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006666 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006667}
6668
6669
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006670RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006671 NoHandleAllocation ha;
6672 ASSERT(args.length() == 2);
6673
6674 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6675 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006676 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006677}
6678
6679
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006680RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006681 NoHandleAllocation ha;
6682 ASSERT(args.length() == 2);
6683
6684 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6685 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006686 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006687}
6688
6689
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006690RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006691 NoHandleAllocation ha;
6692 ASSERT(args.length() == 2);
6693
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006694 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6695 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006696 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6697 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6698 if (x == y) return Smi::FromInt(EQUAL);
6699 Object* result;
6700 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6701 result = Smi::FromInt(EQUAL);
6702 } else {
6703 result = Smi::FromInt(NOT_EQUAL);
6704 }
6705 return result;
6706}
6707
6708
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006709RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006710 NoHandleAllocation ha;
6711 ASSERT(args.length() == 2);
6712
6713 CONVERT_CHECKED(String, x, args[0]);
6714 CONVERT_CHECKED(String, y, args[1]);
6715
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006716 bool not_equal = !x->Equals(y);
6717 // This is slightly convoluted because the value that signifies
6718 // equality is 0 and inequality is 1 so we have to negate the result
6719 // from String::Equals.
6720 ASSERT(not_equal == 0 || not_equal == 1);
6721 STATIC_CHECK(EQUAL == 0);
6722 STATIC_CHECK(NOT_EQUAL == 1);
6723 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006724}
6725
6726
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006727RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006728 NoHandleAllocation ha;
6729 ASSERT(args.length() == 3);
6730
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006731 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6732 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006733 if (isnan(x) || isnan(y)) return args[2];
6734 if (x == y) return Smi::FromInt(EQUAL);
6735 if (isless(x, y)) return Smi::FromInt(LESS);
6736 return Smi::FromInt(GREATER);
6737}
6738
6739
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006740// Compare two Smis as if they were converted to strings and then
6741// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006742RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006743 NoHandleAllocation ha;
6744 ASSERT(args.length() == 2);
6745
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006746 // Extract the integer values from the Smis.
6747 CONVERT_CHECKED(Smi, x, args[0]);
6748 CONVERT_CHECKED(Smi, y, args[1]);
6749 int x_value = x->value();
6750 int y_value = y->value();
6751
6752 // If the integers are equal so are the string representations.
6753 if (x_value == y_value) return Smi::FromInt(EQUAL);
6754
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006755 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006756 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006757 if (x_value == 0 || y_value == 0)
6758 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006759
ager@chromium.org32912102009-01-16 10:38:43 +00006760 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006761 // smallest because the char code of '-' is less than the char code
6762 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006763
6764 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
6765 // architectures using 32-bit Smis.
6766 uint32_t x_scaled = x_value;
6767 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006768 if (x_value < 0 || y_value < 0) {
6769 if (y_value >= 0) return Smi::FromInt(LESS);
6770 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006771 x_scaled = -x_value;
6772 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006773 }
6774
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006775 static const uint32_t kPowersOf10[] = {
6776 1, 10, 100, 1000, 10*1000, 100*1000,
6777 1000*1000, 10*1000*1000, 100*1000*1000,
6778 1000*1000*1000
6779 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006780
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006781 // If the integers have the same number of decimal digits they can be
6782 // compared directly as the numeric order is the same as the
6783 // lexicographic order. If one integer has fewer digits, it is scaled
6784 // by some power of 10 to have the same number of digits as the longer
6785 // integer. If the scaled integers are equal it means the shorter
6786 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006787
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006788 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
6789 int x_log2 = IntegerLog2(x_scaled);
6790 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
6791 x_log10 -= x_scaled < kPowersOf10[x_log10];
6792
6793 int y_log2 = IntegerLog2(y_scaled);
6794 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
6795 y_log10 -= y_scaled < kPowersOf10[y_log10];
6796
6797 int tie = EQUAL;
6798
6799 if (x_log10 < y_log10) {
6800 // X has fewer digits. We would like to simply scale up X but that
6801 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
6802 // be scaled up to 9_000_000_000. So we scale up by the next
6803 // smallest power and scale down Y to drop one digit. It is OK to
6804 // drop one digit from the longer integer since the final digit is
6805 // past the length of the shorter integer.
6806 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
6807 y_scaled /= 10;
6808 tie = LESS;
6809 } else if (y_log10 < x_log10) {
6810 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
6811 x_scaled /= 10;
6812 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006813 }
6814
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006815 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
6816 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
6817 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006818}
6819
6820
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006821static Object* StringInputBufferCompare(RuntimeState* state,
6822 String* x,
6823 String* y) {
6824 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6825 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006826 bufx.Reset(x);
6827 bufy.Reset(y);
6828 while (bufx.has_more() && bufy.has_more()) {
6829 int d = bufx.GetNext() - bufy.GetNext();
6830 if (d < 0) return Smi::FromInt(LESS);
6831 else if (d > 0) return Smi::FromInt(GREATER);
6832 }
6833
6834 // x is (non-trivial) prefix of y:
6835 if (bufy.has_more()) return Smi::FromInt(LESS);
6836 // y is prefix of x:
6837 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6838}
6839
6840
6841static Object* FlatStringCompare(String* x, String* y) {
6842 ASSERT(x->IsFlat());
6843 ASSERT(y->IsFlat());
6844 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6845 int prefix_length = x->length();
6846 if (y->length() < prefix_length) {
6847 prefix_length = y->length();
6848 equal_prefix_result = Smi::FromInt(GREATER);
6849 } else if (y->length() > prefix_length) {
6850 equal_prefix_result = Smi::FromInt(LESS);
6851 }
6852 int r;
6853 if (x->IsAsciiRepresentation()) {
6854 Vector<const char> x_chars = x->ToAsciiVector();
6855 if (y->IsAsciiRepresentation()) {
6856 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006857 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006858 } else {
6859 Vector<const uc16> y_chars = y->ToUC16Vector();
6860 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6861 }
6862 } else {
6863 Vector<const uc16> x_chars = x->ToUC16Vector();
6864 if (y->IsAsciiRepresentation()) {
6865 Vector<const char> y_chars = y->ToAsciiVector();
6866 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6867 } else {
6868 Vector<const uc16> y_chars = y->ToUC16Vector();
6869 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6870 }
6871 }
6872 Object* result;
6873 if (r == 0) {
6874 result = equal_prefix_result;
6875 } else {
6876 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6877 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006878 ASSERT(result ==
6879 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006880 return result;
6881}
6882
6883
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006884RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006885 NoHandleAllocation ha;
6886 ASSERT(args.length() == 2);
6887
6888 CONVERT_CHECKED(String, x, args[0]);
6889 CONVERT_CHECKED(String, y, args[1]);
6890
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006891 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006892
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006893 // A few fast case tests before we flatten.
6894 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006895 if (y->length() == 0) {
6896 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006897 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006898 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006899 return Smi::FromInt(LESS);
6900 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006901
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006902 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006903 if (d < 0) return Smi::FromInt(LESS);
6904 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006905
lrn@chromium.org303ada72010-10-27 09:33:13 +00006906 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006907 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006908 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6909 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006910 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006911 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6912 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006913
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006914 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006915 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006916}
6917
6918
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006919RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006920 NoHandleAllocation ha;
6921 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006922 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006923
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006924 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006925 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006926}
6927
6928
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006929RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006930 NoHandleAllocation ha;
6931 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006932 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006933
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006934 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006935 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006936}
6937
6938
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006939RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006940 NoHandleAllocation ha;
6941 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006942 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006943
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006944 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006945 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006946}
6947
6948
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006949static const double kPiDividedBy4 = 0.78539816339744830962;
6950
6951
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006952RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006953 NoHandleAllocation ha;
6954 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006955 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006956
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006957 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6958 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006959 double result;
6960 if (isinf(x) && isinf(y)) {
6961 // Make sure that the result in case of two infinite arguments
6962 // is a multiple of Pi / 4. The sign of the result is determined
6963 // by the first argument (x) and the sign of the second argument
6964 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006965 int multiplier = (x < 0) ? -1 : 1;
6966 if (y < 0) multiplier *= 3;
6967 result = multiplier * kPiDividedBy4;
6968 } else {
6969 result = atan2(x, y);
6970 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006971 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006972}
6973
6974
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006975RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006976 NoHandleAllocation ha;
6977 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006978 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006979
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006980 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006981 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006982}
6983
6984
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006985RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006986 NoHandleAllocation ha;
6987 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006988 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006989
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006990 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006991 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006992}
6993
6994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006995RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006996 NoHandleAllocation ha;
6997 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006998 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006999
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007000 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007001 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007002}
7003
7004
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007005RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007006 NoHandleAllocation ha;
7007 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007008 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007009
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007010 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007011 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007012}
7013
7014
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007015RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007016 NoHandleAllocation ha;
7017 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007018 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007019
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007020 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007021 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007022}
7023
7024
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007025RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007026 NoHandleAllocation ha;
7027 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007028 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007029
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007030 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007031
7032 // If the second argument is a smi, it is much faster to call the
7033 // custom powi() function than the generic pow().
7034 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007035 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007036 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007037 }
7038
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007039 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007040 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007041}
7042
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007043// Fast version of Math.pow if we know that y is not an integer and
7044// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007045RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007046 NoHandleAllocation ha;
7047 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007048 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7049 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007050 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007051 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007052 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007053 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007054 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007055 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007056 }
7057}
7058
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007059
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007060RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007061 NoHandleAllocation ha;
7062 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007063 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007064
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007065 if (!args[0]->IsHeapNumber()) {
7066 // Must be smi. Return the argument unchanged for all the other types
7067 // to make fuzz-natives test happy.
7068 return args[0];
7069 }
7070
7071 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7072
7073 double value = number->value();
7074 int exponent = number->get_exponent();
7075 int sign = number->get_sign();
7076
danno@chromium.org160a7b02011-04-18 15:51:38 +00007077 if (exponent < -1) {
7078 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7079 if (sign) return isolate->heap()->minus_zero_value();
7080 return Smi::FromInt(0);
7081 }
7082
7083 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7084 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7085 // agument holds for 32-bit smis).
7086 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007087 return Smi::FromInt(static_cast<int>(value + 0.5));
7088 }
7089
7090 // If the magnitude is big enough, there's no place for fraction part. If we
7091 // try to add 0.5 to this number, 1.0 will be added instead.
7092 if (exponent >= 52) {
7093 return number;
7094 }
7095
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007096 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007097
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007098 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007099 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007100}
7101
7102
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007103RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007104 NoHandleAllocation ha;
7105 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007106 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007107
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007108 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007109 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007110}
7111
7112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007113RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007114 NoHandleAllocation ha;
7115 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007116 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007117
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007118 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007119 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007120}
7121
7122
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007123RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007124 NoHandleAllocation ha;
7125 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007126 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007127
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007128 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007129 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007130}
7131
7132
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007133static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007134 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7135 181, 212, 243, 273, 304, 334};
7136 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7137 182, 213, 244, 274, 305, 335};
7138
7139 year += month / 12;
7140 month %= 12;
7141 if (month < 0) {
7142 year--;
7143 month += 12;
7144 }
7145
7146 ASSERT(month >= 0);
7147 ASSERT(month < 12);
7148
7149 // year_delta is an arbitrary number such that:
7150 // a) year_delta = -1 (mod 400)
7151 // b) year + year_delta > 0 for years in the range defined by
7152 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7153 // Jan 1 1970. This is required so that we don't run into integer
7154 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007155 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007156 // operations.
7157 static const int year_delta = 399999;
7158 static const int base_day = 365 * (1970 + year_delta) +
7159 (1970 + year_delta) / 4 -
7160 (1970 + year_delta) / 100 +
7161 (1970 + year_delta) / 400;
7162
7163 int year1 = year + year_delta;
7164 int day_from_year = 365 * year1 +
7165 year1 / 4 -
7166 year1 / 100 +
7167 year1 / 400 -
7168 base_day;
7169
7170 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007171 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007172 }
7173
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007174 return day_from_year + day_from_month_leap[month] + day - 1;
7175}
7176
7177
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007178RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007179 NoHandleAllocation ha;
7180 ASSERT(args.length() == 3);
7181
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007182 CONVERT_SMI_ARG_CHECKED(year, 0);
7183 CONVERT_SMI_ARG_CHECKED(month, 1);
7184 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007185
7186 return Smi::FromInt(MakeDay(year, month, date));
7187}
7188
7189
7190static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7191static const int kDaysIn4Years = 4 * 365 + 1;
7192static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7193static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7194static const int kDays1970to2000 = 30 * 365 + 7;
7195static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7196 kDays1970to2000;
7197static const int kYearsOffset = 400000;
7198
7199static const char kDayInYear[] = {
7200 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7201 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7202 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7203 22, 23, 24, 25, 26, 27, 28,
7204 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7205 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7206 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7207 22, 23, 24, 25, 26, 27, 28, 29, 30,
7208 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7209 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7210 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7211 22, 23, 24, 25, 26, 27, 28, 29, 30,
7212 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7213 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7214 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7215 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7216 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7217 22, 23, 24, 25, 26, 27, 28, 29, 30,
7218 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7219 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7220 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7221 22, 23, 24, 25, 26, 27, 28, 29, 30,
7222 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7223 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7224
7225 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7226 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7227 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7228 22, 23, 24, 25, 26, 27, 28,
7229 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7230 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7231 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7232 22, 23, 24, 25, 26, 27, 28, 29, 30,
7233 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7234 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7235 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7236 22, 23, 24, 25, 26, 27, 28, 29, 30,
7237 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7238 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7239 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7240 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7241 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7242 22, 23, 24, 25, 26, 27, 28, 29, 30,
7243 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7244 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7245 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7246 22, 23, 24, 25, 26, 27, 28, 29, 30,
7247 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7248 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7249
7250 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7251 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7252 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7253 22, 23, 24, 25, 26, 27, 28, 29,
7254 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7255 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7256 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7257 22, 23, 24, 25, 26, 27, 28, 29, 30,
7258 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7259 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7260 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7261 22, 23, 24, 25, 26, 27, 28, 29, 30,
7262 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7263 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7264 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7265 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7266 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7267 22, 23, 24, 25, 26, 27, 28, 29, 30,
7268 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7269 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7270 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7271 22, 23, 24, 25, 26, 27, 28, 29, 30,
7272 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7273 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7274
7275 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7276 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7277 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7278 22, 23, 24, 25, 26, 27, 28,
7279 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7280 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7281 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7282 22, 23, 24, 25, 26, 27, 28, 29, 30,
7283 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7284 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7285 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7286 22, 23, 24, 25, 26, 27, 28, 29, 30,
7287 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7288 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7289 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7290 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7291 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7292 22, 23, 24, 25, 26, 27, 28, 29, 30,
7293 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7294 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7295 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7296 22, 23, 24, 25, 26, 27, 28, 29, 30,
7297 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7298 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7299
7300static const char kMonthInYear[] = {
7301 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,
7302 0, 0, 0, 0, 0, 0,
7303 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,
7304 1, 1, 1,
7305 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,
7306 2, 2, 2, 2, 2, 2,
7307 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,
7308 3, 3, 3, 3, 3,
7309 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,
7310 4, 4, 4, 4, 4, 4,
7311 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,
7312 5, 5, 5, 5, 5,
7313 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,
7314 6, 6, 6, 6, 6, 6,
7315 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,
7316 7, 7, 7, 7, 7, 7,
7317 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,
7318 8, 8, 8, 8, 8,
7319 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,
7320 9, 9, 9, 9, 9, 9,
7321 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7322 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7323 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7324 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7325
7326 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,
7327 0, 0, 0, 0, 0, 0,
7328 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,
7329 1, 1, 1,
7330 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,
7331 2, 2, 2, 2, 2, 2,
7332 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,
7333 3, 3, 3, 3, 3,
7334 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,
7335 4, 4, 4, 4, 4, 4,
7336 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,
7337 5, 5, 5, 5, 5,
7338 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,
7339 6, 6, 6, 6, 6, 6,
7340 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,
7341 7, 7, 7, 7, 7, 7,
7342 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,
7343 8, 8, 8, 8, 8,
7344 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,
7345 9, 9, 9, 9, 9, 9,
7346 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7347 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7348 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7349 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7350
7351 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,
7352 0, 0, 0, 0, 0, 0,
7353 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,
7354 1, 1, 1, 1,
7355 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,
7356 2, 2, 2, 2, 2, 2,
7357 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,
7358 3, 3, 3, 3, 3,
7359 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,
7360 4, 4, 4, 4, 4, 4,
7361 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,
7362 5, 5, 5, 5, 5,
7363 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,
7364 6, 6, 6, 6, 6, 6,
7365 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,
7366 7, 7, 7, 7, 7, 7,
7367 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,
7368 8, 8, 8, 8, 8,
7369 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,
7370 9, 9, 9, 9, 9, 9,
7371 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7372 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7373 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7374 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7375
7376 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,
7377 0, 0, 0, 0, 0, 0,
7378 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,
7379 1, 1, 1,
7380 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,
7381 2, 2, 2, 2, 2, 2,
7382 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,
7383 3, 3, 3, 3, 3,
7384 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,
7385 4, 4, 4, 4, 4, 4,
7386 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,
7387 5, 5, 5, 5, 5,
7388 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,
7389 6, 6, 6, 6, 6, 6,
7390 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,
7391 7, 7, 7, 7, 7, 7,
7392 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,
7393 8, 8, 8, 8, 8,
7394 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,
7395 9, 9, 9, 9, 9, 9,
7396 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7397 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7398 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7399 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7400
7401
7402// This function works for dates from 1970 to 2099.
7403static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007404 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007405#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007406 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007407#endif
7408
7409 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7410 date %= kDaysIn4Years;
7411
7412 month = kMonthInYear[date];
7413 day = kDayInYear[date];
7414
7415 ASSERT(MakeDay(year, month, day) == save_date);
7416}
7417
7418
7419static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007420 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007421#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007422 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007423#endif
7424
7425 date += kDaysOffset;
7426 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7427 date %= kDaysIn400Years;
7428
7429 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7430
7431 date--;
7432 int yd1 = date / kDaysIn100Years;
7433 date %= kDaysIn100Years;
7434 year += 100 * yd1;
7435
7436 date++;
7437 int yd2 = date / kDaysIn4Years;
7438 date %= kDaysIn4Years;
7439 year += 4 * yd2;
7440
7441 date--;
7442 int yd3 = date / 365;
7443 date %= 365;
7444 year += yd3;
7445
7446 bool is_leap = (!yd1 || yd2) && !yd3;
7447
7448 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007449 ASSERT(is_leap || (date >= 0));
7450 ASSERT((date < 365) || (is_leap && (date < 366)));
7451 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7452 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7453 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007454
7455 if (is_leap) {
7456 day = kDayInYear[2*365 + 1 + date];
7457 month = kMonthInYear[2*365 + 1 + date];
7458 } else {
7459 day = kDayInYear[date];
7460 month = kMonthInYear[date];
7461 }
7462
7463 ASSERT(MakeDay(year, month, day) == save_date);
7464}
7465
7466
7467static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007468 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007469 if (date >= 0 && date < 32 * kDaysIn4Years) {
7470 DateYMDFromTimeAfter1970(date, year, month, day);
7471 } else {
7472 DateYMDFromTimeSlow(date, year, month, day);
7473 }
7474}
7475
7476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007477RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007478 NoHandleAllocation ha;
7479 ASSERT(args.length() == 2);
7480
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007481 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007482 CONVERT_CHECKED(JSArray, res_array, args[1]);
7483
7484 int year, month, day;
7485 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7486
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007487 RUNTIME_ASSERT(res_array->elements()->map() ==
7488 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007489 FixedArray* elms = FixedArray::cast(res_array->elements());
7490 RUNTIME_ASSERT(elms->length() == 3);
7491
7492 elms->set(0, Smi::FromInt(year));
7493 elms->set(1, Smi::FromInt(month));
7494 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007495
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007496 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007497}
7498
7499
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007500RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007501 HandleScope scope(isolate);
7502 ASSERT(args.length() == 3);
7503
7504 Handle<JSFunction> callee = args.at<JSFunction>(0);
7505 Object** parameters = reinterpret_cast<Object**>(args[1]);
7506 const int argument_count = Smi::cast(args[2])->value();
7507
7508 Handle<JSObject> result =
7509 isolate->factory()->NewArgumentsObject(callee, argument_count);
7510 // Allocate the elements if needed.
7511 int parameter_count = callee->shared()->formal_parameter_count();
7512 if (argument_count > 0) {
7513 if (parameter_count > 0) {
7514 int mapped_count = Min(argument_count, parameter_count);
7515 Handle<FixedArray> parameter_map =
7516 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7517 parameter_map->set_map(
7518 isolate->heap()->non_strict_arguments_elements_map());
7519
7520 Handle<Map> old_map(result->map());
7521 Handle<Map> new_map =
7522 isolate->factory()->CopyMapDropTransitions(old_map);
7523 new_map->set_elements_kind(JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
7524
7525 result->set_map(*new_map);
7526 result->set_elements(*parameter_map);
7527
7528 // Store the context and the arguments array at the beginning of the
7529 // parameter map.
7530 Handle<Context> context(isolate->context());
7531 Handle<FixedArray> arguments =
7532 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7533 parameter_map->set(0, *context);
7534 parameter_map->set(1, *arguments);
7535
7536 // Loop over the actual parameters backwards.
7537 int index = argument_count - 1;
7538 while (index >= mapped_count) {
7539 // These go directly in the arguments array and have no
7540 // corresponding slot in the parameter map.
7541 arguments->set(index, *(parameters - index - 1));
7542 --index;
7543 }
7544
7545 ScopeInfo<> scope_info(callee->shared()->scope_info());
7546 while (index >= 0) {
7547 // Detect duplicate names to the right in the parameter list.
7548 Handle<String> name = scope_info.parameter_name(index);
7549 int context_slot_count = scope_info.number_of_context_slots();
7550 bool duplicate = false;
7551 for (int j = index + 1; j < parameter_count; ++j) {
7552 if (scope_info.parameter_name(j).is_identical_to(name)) {
7553 duplicate = true;
7554 break;
7555 }
7556 }
7557
7558 if (duplicate) {
7559 // This goes directly in the arguments array with a hole in the
7560 // parameter map.
7561 arguments->set(index, *(parameters - index - 1));
7562 parameter_map->set_the_hole(index + 2);
7563 } else {
7564 // The context index goes in the parameter map with a hole in the
7565 // arguments array.
7566 int context_index = -1;
7567 for (int j = Context::MIN_CONTEXT_SLOTS;
7568 j < context_slot_count;
7569 ++j) {
7570 if (scope_info.context_slot_name(j).is_identical_to(name)) {
7571 context_index = j;
7572 break;
7573 }
7574 }
7575 ASSERT(context_index >= 0);
7576 arguments->set_the_hole(index);
7577 parameter_map->set(index + 2, Smi::FromInt(context_index));
7578 }
7579
7580 --index;
7581 }
7582 } else {
7583 // If there is no aliasing, the arguments object elements are not
7584 // special in any way.
7585 Handle<FixedArray> elements =
7586 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7587 result->set_elements(*elements);
7588 for (int i = 0; i < argument_count; ++i) {
7589 elements->set(i, *(parameters - i - 1));
7590 }
7591 }
7592 }
7593 return *result;
7594}
7595
7596
7597RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007598 NoHandleAllocation ha;
7599 ASSERT(args.length() == 3);
7600
7601 JSFunction* callee = JSFunction::cast(args[0]);
7602 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007603 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007604
lrn@chromium.org303ada72010-10-27 09:33:13 +00007605 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007606 { MaybeObject* maybe_result =
7607 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007608 if (!maybe_result->ToObject(&result)) return maybe_result;
7609 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007610 // Allocate the elements if needed.
7611 if (length > 0) {
7612 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007613 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007614 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007615 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7616 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007617
7618 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007619 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007620 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007621 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007622
7623 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007624 for (int i = 0; i < length; i++) {
7625 array->set(i, *--parameters, mode);
7626 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007627 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007628 }
7629 return result;
7630}
7631
7632
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007633RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007634 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007635 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007636 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007637 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007638 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007639
whesse@chromium.org7b260152011-06-20 15:33:18 +00007640 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007641 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007642 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007643 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007644 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7645 context,
7646 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007647 return *result;
7648}
7649
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007650
7651static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7652 int* total_argc) {
7653 // Find frame containing arguments passed to the caller.
7654 JavaScriptFrameIterator it;
7655 JavaScriptFrame* frame = it.frame();
7656 List<JSFunction*> functions(2);
7657 frame->GetFunctions(&functions);
7658 if (functions.length() > 1) {
7659 int inlined_frame_index = functions.length() - 1;
7660 JSFunction* inlined_function = functions[inlined_frame_index];
7661 int args_count = inlined_function->shared()->formal_parameter_count();
7662 ScopedVector<SlotRef> args_slots(args_count);
7663 SlotRef::ComputeSlotMappingForArguments(frame,
7664 inlined_frame_index,
7665 &args_slots);
7666
7667 *total_argc = bound_argc + args_count;
7668 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7669 for (int i = 0; i < args_count; i++) {
7670 Handle<Object> val = args_slots[i].GetValue();
7671 param_data[bound_argc + i] = val.location();
7672 }
7673 return param_data;
7674 } else {
7675 it.AdvanceToArgumentsFrame();
7676 frame = it.frame();
7677 int args_count = frame->ComputeParametersCount();
7678
7679 *total_argc = bound_argc + args_count;
7680 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7681 for (int i = 0; i < args_count; i++) {
7682 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7683 param_data[bound_argc + i] = val.location();
7684 }
7685 return param_data;
7686 }
7687}
7688
7689
7690RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007691 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007692 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007693 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007694 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007695
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007696 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007697 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007698 int bound_argc = 0;
7699 if (!args[1]->IsNull()) {
7700 CONVERT_ARG_CHECKED(JSArray, params, 1);
7701 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007702 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007703 bound_argc = Smi::cast(params->length())->value();
7704 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007705
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007706 int total_argc = 0;
7707 SmartPointer<Object**> param_data =
7708 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007709 for (int i = 0; i < bound_argc; i++) {
7710 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007711 param_data[i] = val.location();
7712 }
7713
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007714 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007715 Handle<Object> result =
7716 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007717 if (exception) {
7718 return Failure::Exception();
7719 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007720
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007721 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007722 return *result;
7723}
7724
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007725
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007726static void TrySettingInlineConstructStub(Isolate* isolate,
7727 Handle<JSFunction> function) {
7728 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007729 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007730 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007731 }
7732 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007733 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007734 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007735 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007736 function->shared()->set_construct_stub(
7737 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007738 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007739 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007740}
7741
7742
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007743RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007744 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007745 ASSERT(args.length() == 1);
7746
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007747 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007748
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007749 // If the constructor isn't a proper function we throw a type error.
7750 if (!constructor->IsJSFunction()) {
7751 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7752 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007753 isolate->factory()->NewTypeError("not_constructor", arguments);
7754 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007755 }
7756
7757 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007758
7759 // If function should not have prototype, construction is not allowed. In this
7760 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007761 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007762 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7763 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007764 isolate->factory()->NewTypeError("not_constructor", arguments);
7765 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007766 }
7767
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007768#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007769 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007770 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007771 if (debug->StepInActive()) {
7772 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007773 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007774#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007775
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007776 if (function->has_initial_map()) {
7777 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007778 // The 'Function' function ignores the receiver object when
7779 // called using 'new' and creates a new JSFunction object that
7780 // is returned. The receiver object is only used for error
7781 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007782 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007783 // allocate JSFunctions since it does not properly initialize
7784 // the shared part of the function. Since the receiver is
7785 // ignored anyway, we use the global object as the receiver
7786 // instead of a new JSFunction object. This way, errors are
7787 // reported the same way whether or not 'Function' is called
7788 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007789 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007790 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007791 }
7792
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007793 // The function should be compiled for the optimization hints to be
7794 // available. We cannot use EnsureCompiled because that forces a
7795 // compilation through the shared function info which makes it
7796 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007797 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007798 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007799
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007800 if (!function->has_initial_map() &&
7801 shared->IsInobjectSlackTrackingInProgress()) {
7802 // The tracking is already in progress for another function. We can only
7803 // track one initial_map at a time, so we force the completion before the
7804 // function is called as a constructor for the first time.
7805 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007806 }
7807
7808 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007809 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7810 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007811 // Delay setting the stub if inobject slack tracking is in progress.
7812 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007813 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007814 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007815
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007816 isolate->counters()->constructed_objects()->Increment();
7817 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007818
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007819 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007820}
7821
7822
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007823RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007824 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007825 ASSERT(args.length() == 1);
7826
7827 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7828 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007829 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007830
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007831 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007832}
7833
7834
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007835RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007836 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007837 ASSERT(args.length() == 1);
7838
7839 Handle<JSFunction> function = args.at<JSFunction>(0);
7840#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007841 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007842 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007843 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007844 PrintF("]\n");
7845 }
7846#endif
7847
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007848 // Compile the target function. Here we compile using CompileLazyInLoop in
7849 // order to get the optimized version. This helps code like delta-blue
7850 // that calls performance-critical routines through constructors. A
7851 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7852 // direct call. Since the in-loop tracking takes place through CallICs
7853 // this means that things called through constructors are never known to
7854 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007855 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007856 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007857 return Failure::Exception();
7858 }
7859
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007860 // All done. Return the compiled code.
7861 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007862 return function->code();
7863}
7864
7865
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007866RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007867 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007868 ASSERT(args.length() == 1);
7869 Handle<JSFunction> function = args.at<JSFunction>(0);
7870 // If the function is not optimizable or debugger is active continue using the
7871 // code from the full compiler.
7872 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007873 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007874 if (FLAG_trace_opt) {
7875 PrintF("[failed to optimize ");
7876 function->PrintName();
7877 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7878 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007879 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007880 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007881 function->ReplaceCode(function->shared()->code());
7882 return function->code();
7883 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007884 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007885 return function->code();
7886 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007887 if (FLAG_trace_opt) {
7888 PrintF("[failed to optimize ");
7889 function->PrintName();
7890 PrintF(": optimized compilation failed]\n");
7891 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007892 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007893 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007894}
7895
7896
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007897RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007898 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007899 ASSERT(args.length() == 1);
7900 RUNTIME_ASSERT(args[0]->IsSmi());
7901 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007902 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007903 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7904 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007905 int frames = deoptimizer->output_count();
7906
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007907 deoptimizer->MaterializeHeapNumbers();
7908 delete deoptimizer;
7909
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007910 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007911 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007912 for (int i = 0; i < frames - 1; i++) it.Advance();
7913 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007914
7915 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007916 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007917 Handle<Object> arguments;
7918 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007919 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007920 if (arguments.is_null()) {
7921 // FunctionGetArguments can't throw an exception, so cast away the
7922 // doubt with an assert.
7923 arguments = Handle<Object>(
7924 Accessors::FunctionGetArguments(*function,
7925 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007926 ASSERT(*arguments != isolate->heap()->null_value());
7927 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007928 }
7929 frame->SetExpression(i, *arguments);
7930 }
7931 }
7932
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007933 if (type == Deoptimizer::EAGER) {
7934 RUNTIME_ASSERT(function->IsOptimized());
7935 } else {
7936 RUNTIME_ASSERT(!function->IsOptimized());
7937 }
7938
7939 // Avoid doing too much work when running with --always-opt and keep
7940 // the optimized code around.
7941 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007942 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007943 }
7944
7945 // Count the number of optimized activations of the function.
7946 int activations = 0;
7947 while (!it.done()) {
7948 JavaScriptFrame* frame = it.frame();
7949 if (frame->is_optimized() && frame->function() == *function) {
7950 activations++;
7951 }
7952 it.Advance();
7953 }
7954
7955 // TODO(kasperl): For now, we cannot support removing the optimized
7956 // code when we have recursive invocations of the same function.
7957 if (activations == 0) {
7958 if (FLAG_trace_deopt) {
7959 PrintF("[removing optimized code for: ");
7960 function->PrintName();
7961 PrintF("]\n");
7962 }
7963 function->ReplaceCode(function->shared()->code());
7964 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007965 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007966}
7967
7968
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007969RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007970 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007971 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007972 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007973}
7974
7975
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007976RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007977 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007978 ASSERT(args.length() == 1);
7979 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007980 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007981
7982 Deoptimizer::DeoptimizeFunction(*function);
7983
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007984 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007985}
7986
7987
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007988RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
7989#if defined(USE_SIMULATOR)
7990 return isolate->heap()->true_value();
7991#else
7992 return isolate->heap()->false_value();
7993#endif
7994}
7995
7996
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007997RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7998 HandleScope scope(isolate);
7999 ASSERT(args.length() == 1);
8000 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8001 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8002 function->MarkForLazyRecompilation();
8003 return isolate->heap()->undefined_value();
8004}
8005
8006
lrn@chromium.org1c092762011-05-09 09:42:16 +00008007RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8008 HandleScope scope(isolate);
8009 ASSERT(args.length() == 1);
8010 if (!V8::UseCrankshaft()) {
8011 return Smi::FromInt(4); // 4 == "never".
8012 }
8013 if (FLAG_always_opt) {
8014 return Smi::FromInt(3); // 3 == "always".
8015 }
8016 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8017 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8018 : Smi::FromInt(2); // 2 == "no".
8019}
8020
8021
8022RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8023 HandleScope scope(isolate);
8024 ASSERT(args.length() == 1);
8025 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8026 return Smi::FromInt(function->shared()->opt_count());
8027}
8028
8029
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008030RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008031 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008032 ASSERT(args.length() == 1);
8033 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8034
8035 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008036 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008037
8038 // We have hit a back edge in an unoptimized frame for a function that was
8039 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008040 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008041 // Keep track of whether we've succeeded in optimizing.
8042 bool succeeded = unoptimized->optimizable();
8043 if (succeeded) {
8044 // If we are trying to do OSR when there are already optimized
8045 // activations of the function, it means (a) the function is directly or
8046 // indirectly recursive and (b) an optimized invocation has been
8047 // deoptimized so that we are currently in an unoptimized activation.
8048 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008049 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008050 while (succeeded && !it.done()) {
8051 JavaScriptFrame* frame = it.frame();
8052 succeeded = !frame->is_optimized() || frame->function() != *function;
8053 it.Advance();
8054 }
8055 }
8056
8057 int ast_id = AstNode::kNoNumber;
8058 if (succeeded) {
8059 // The top JS function is this one, the PC is somewhere in the
8060 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008061 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008062 JavaScriptFrame* frame = it.frame();
8063 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008064 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008065 ASSERT(unoptimized->contains(frame->pc()));
8066
8067 // Use linear search of the unoptimized code's stack check table to find
8068 // the AST id matching the PC.
8069 Address start = unoptimized->instruction_start();
8070 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008071 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008072 uint32_t table_length = Memory::uint32_at(table_cursor);
8073 table_cursor += kIntSize;
8074 for (unsigned i = 0; i < table_length; ++i) {
8075 // Table entries are (AST id, pc offset) pairs.
8076 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8077 if (pc_offset == target_pc_offset) {
8078 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8079 break;
8080 }
8081 table_cursor += 2 * kIntSize;
8082 }
8083 ASSERT(ast_id != AstNode::kNoNumber);
8084 if (FLAG_trace_osr) {
8085 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8086 function->PrintName();
8087 PrintF("]\n");
8088 }
8089
8090 // Try to compile the optimized code. A true return value from
8091 // CompileOptimized means that compilation succeeded, not necessarily
8092 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008093 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
8094 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008095 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8096 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008097 if (data->OsrPcOffset()->value() >= 0) {
8098 if (FLAG_trace_osr) {
8099 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008100 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008101 }
8102 ASSERT(data->OsrAstId()->value() == ast_id);
8103 } else {
8104 // We may never generate the desired OSR entry if we emit an
8105 // early deoptimize.
8106 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008107 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008108 } else {
8109 succeeded = false;
8110 }
8111 }
8112
8113 // Revert to the original stack checks in the original unoptimized code.
8114 if (FLAG_trace_osr) {
8115 PrintF("[restoring original stack checks in ");
8116 function->PrintName();
8117 PrintF("]\n");
8118 }
8119 StackCheckStub check_stub;
8120 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008121 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008122 Deoptimizer::RevertStackCheckCode(*unoptimized,
8123 *check_code,
8124 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008125
8126 // Allow OSR only at nesting level zero again.
8127 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8128
8129 // If the optimization attempt succeeded, return the AST id tagged as a
8130 // smi. This tells the builtin that we need to translate the unoptimized
8131 // frame to an optimized one.
8132 if (succeeded) {
8133 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8134 return Smi::FromInt(ast_id);
8135 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008136 if (function->IsMarkedForLazyRecompilation()) {
8137 function->ReplaceCode(function->shared()->code());
8138 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008139 return Smi::FromInt(-1);
8140 }
8141}
8142
8143
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008144RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008145 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008146 ASSERT(args.length() == 1);
8147 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8148 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8149}
8150
8151
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008152RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008153 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008154 ASSERT(args.length() == 1);
8155 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8156 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8157}
8158
8159
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008160RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008161 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008162 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008163
kasper.lund7276f142008-07-30 08:49:36 +00008164 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00008165 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008166 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008167 { MaybeObject* maybe_result =
8168 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008169 if (!maybe_result->ToObject(&result)) return maybe_result;
8170 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008171
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008172 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008173
kasper.lund7276f142008-07-30 08:49:36 +00008174 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008175}
8176
lrn@chromium.org303ada72010-10-27 09:33:13 +00008177
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008178RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8179 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008180 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008181 JSObject* extension_object;
8182 if (args[0]->IsJSObject()) {
8183 extension_object = JSObject::cast(args[0]);
8184 } else {
8185 // Convert the object to a proper JavaScript object.
8186 MaybeObject* maybe_js_object = args[0]->ToObject();
8187 if (!maybe_js_object->To(&extension_object)) {
8188 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8189 HandleScope scope(isolate);
8190 Handle<Object> handle = args.at<Object>(0);
8191 Handle<Object> result =
8192 isolate->factory()->NewTypeError("with_expression",
8193 HandleVector(&handle, 1));
8194 return isolate->Throw(*result);
8195 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008196 return maybe_js_object;
8197 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008198 }
8199 }
8200
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008201 JSFunction* function;
8202 if (args[1]->IsSmi()) {
8203 // A smi sentinel indicates a context nested inside global code rather
8204 // than some function. There is a canonical empty function that can be
8205 // gotten from the global context.
8206 function = isolate->context()->global_context()->closure();
8207 } else {
8208 function = JSFunction::cast(args[1]);
8209 }
8210
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008211 Context* context;
8212 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008213 isolate->heap()->AllocateWithContext(function,
8214 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008215 extension_object);
8216 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008217 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008218 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008219}
8220
8221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008222RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008223 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008224 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008225 String* name = String::cast(args[0]);
8226 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008227 JSFunction* function;
8228 if (args[2]->IsSmi()) {
8229 // A smi sentinel indicates a context nested inside global code rather
8230 // than some function. There is a canonical empty function that can be
8231 // gotten from the global context.
8232 function = isolate->context()->global_context()->closure();
8233 } else {
8234 function = JSFunction::cast(args[2]);
8235 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008236 Context* context;
8237 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008238 isolate->heap()->AllocateCatchContext(function,
8239 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008240 name,
8241 thrown_object);
8242 if (!maybe_context->To(&context)) return maybe_context;
8243 isolate->set_context(context);
8244 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008245}
8246
8247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008248RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008249 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008250 ASSERT(args.length() == 2);
8251
8252 CONVERT_ARG_CHECKED(Context, context, 0);
8253 CONVERT_ARG_CHECKED(String, name, 1);
8254
8255 int index;
8256 PropertyAttributes attributes;
8257 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008258 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008259
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008260 // If the slot was not found the result is true.
8261 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008262 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008263 }
8264
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008265 // If the slot was found in a context, it should be DONT_DELETE.
8266 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008267 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008268 }
8269
8270 // The slot was found in a JSObject, either a context extension object,
8271 // the global object, or an arguments object. Try to delete it
8272 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
8273 // which allows deleting all parameters in functions that mention
8274 // 'arguments', we do this even for the case of slots found on an
8275 // arguments object. The slot was found on an arguments object if the
8276 // index is non-negative.
8277 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8278 if (index >= 0) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008279 return object->DeleteElement(index, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008280 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008281 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008282 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008283}
8284
8285
ager@chromium.orga1645e22009-09-09 19:27:10 +00008286// A mechanism to return a pair of Object pointers in registers (if possible).
8287// How this is achieved is calling convention-dependent.
8288// All currently supported x86 compiles uses calling conventions that are cdecl
8289// variants where a 64-bit value is returned in two 32-bit registers
8290// (edx:eax on ia32, r1:r0 on ARM).
8291// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8292// In Win64 calling convention, a struct of two pointers is returned in memory,
8293// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008294#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008295struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008296 MaybeObject* x;
8297 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008298};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008299
lrn@chromium.org303ada72010-10-27 09:33:13 +00008300static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008301 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008302 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8303 // In Win64 they are assigned to a hidden first argument.
8304 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008305}
8306#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008307typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008308static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008309 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008310 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008311}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008312#endif
8313
8314
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008315static inline MaybeObject* Unhole(Heap* heap,
8316 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008317 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008318 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8319 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008320 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008321}
8322
8323
danno@chromium.org40cb8782011-05-25 07:58:50 +00008324static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8325 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008326 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008327 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008328 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008329 JSFunction* context_extension_function =
8330 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008331 // If the holder isn't a context extension object, we just return it
8332 // as the receiver. This allows arguments objects to be used as
8333 // receivers, but only if they are put in the context scope chain
8334 // explicitly via a with-statement.
8335 Object* constructor = holder->map()->constructor();
8336 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008337 // Fall back to using the global object as the implicit receiver if
8338 // the property turns out to be a local variable allocated in a
8339 // context extension object - introduced via eval. Implicit global
8340 // receivers are indicated with the hole value.
8341 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008342}
8343
8344
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008345static ObjectPair LoadContextSlotHelper(Arguments args,
8346 Isolate* isolate,
8347 bool throw_error) {
8348 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008349 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008350
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008351 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008352 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008353 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008354 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008355 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008356
8357 int index;
8358 PropertyAttributes attributes;
8359 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008360 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008361
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008362 // If the index is non-negative, the slot has been found in a local
8363 // variable or a parameter. Read it from the context object or the
8364 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008365 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008366 // If the "property" we were looking for is a local variable or an
8367 // argument in a context, the receiver is the global object; see
8368 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008369 //
8370 // Use the hole as the receiver to signal that the receiver is
8371 // implicit and that the global receiver should be used.
8372 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008373 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008374 ? Context::cast(*holder)->get(index)
8375 : JSObject::cast(*holder)->GetElement(index);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008376 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008377 }
8378
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008379 // If the holder is found, we read the property from it.
8380 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008381 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008382 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008383 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008384 if (object->IsGlobalObject()) {
8385 receiver = GlobalObject::cast(object)->global_receiver();
8386 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008387 // Use the hole as the receiver to signal that the receiver is
8388 // implicit and that the global receiver should be used.
8389 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008390 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008391 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008392 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008393
8394 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008395 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008396
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008397 // No need to unhole the value here. This is taken care of by the
8398 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008399 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008400 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008401 }
8402
8403 if (throw_error) {
8404 // The property doesn't exist - throw exception.
8405 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008406 isolate->factory()->NewReferenceError("not_defined",
8407 HandleVector(&name, 1));
8408 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008409 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008410 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008411 return MakePair(isolate->heap()->undefined_value(),
8412 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008413 }
8414}
8415
8416
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008417RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008418 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008419}
8420
8421
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008422RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008423 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008424}
8425
8426
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008427RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008428 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008429 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008430
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008431 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008432 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008433 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008434 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008435 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8436 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008437 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008438
8439 int index;
8440 PropertyAttributes attributes;
8441 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008442 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008443
8444 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008445 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008446 // Ignore if read_only variable.
8447 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008448 // Context is a fixed array and set cannot fail.
8449 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008450 } else if (strict_mode == kStrictMode) {
8451 // Setting read only property in strict mode.
8452 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008453 isolate->factory()->NewTypeError("strict_cannot_assign",
8454 HandleVector(&name, 1));
8455 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008456 }
8457 } else {
8458 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008459 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008460 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008461 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008462 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008463 return Failure::Exception();
8464 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008465 }
8466 return *value;
8467 }
8468
8469 // Slow case: The property is not in a FixedArray context.
8470 // It is either in an JSObject extension context or it was not found.
8471 Handle<JSObject> context_ext;
8472
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008473 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008474 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008475 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008476 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008477 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008478 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008479
8480 if (strict_mode == kStrictMode) {
8481 // Throw in strict mode (assignment to undefined variable).
8482 Handle<Object> error =
8483 isolate->factory()->NewReferenceError(
8484 "not_defined", HandleVector(&name, 1));
8485 return isolate->Throw(*error);
8486 }
8487 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008488 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008489 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008490 }
8491
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008492 // Set the property, but ignore if read_only variable on the context
8493 // extension object itself.
8494 if ((attributes & READ_ONLY) == 0 ||
8495 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008496 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008497 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008498 SetProperty(context_ext, name, value, NONE, strict_mode));
8499 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008500 // Setting read only property in strict mode.
8501 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008502 isolate->factory()->NewTypeError(
8503 "strict_cannot_assign", HandleVector(&name, 1));
8504 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008505 }
8506 return *value;
8507}
8508
8509
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008510RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008511 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008512 ASSERT(args.length() == 1);
8513
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008514 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008515}
8516
8517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008518RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008519 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008520 ASSERT(args.length() == 1);
8521
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008522 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008523}
8524
8525
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008526RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008527 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008528 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008529}
8530
8531
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008532RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008533 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008534 ASSERT(args.length() == 1);
8535
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008536 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008537 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008538 isolate->factory()->NewReferenceError("not_defined",
8539 HandleVector(&name, 1));
8540 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008541}
8542
8543
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008544RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008545 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008546
8547 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008548 if (isolate->stack_guard()->IsStackOverflow()) {
8549 NoHandleAllocation na;
8550 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008551 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008552
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008553 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008554}
8555
8556
8557// NOTE: These PrintXXX functions are defined for all builds (not just
8558// DEBUG builds) because we may want to be able to trace function
8559// calls in all modes.
8560static void PrintString(String* str) {
8561 // not uncommon to have empty strings
8562 if (str->length() > 0) {
8563 SmartPointer<char> s =
8564 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8565 PrintF("%s", *s);
8566 }
8567}
8568
8569
8570static void PrintObject(Object* obj) {
8571 if (obj->IsSmi()) {
8572 PrintF("%d", Smi::cast(obj)->value());
8573 } else if (obj->IsString() || obj->IsSymbol()) {
8574 PrintString(String::cast(obj));
8575 } else if (obj->IsNumber()) {
8576 PrintF("%g", obj->Number());
8577 } else if (obj->IsFailure()) {
8578 PrintF("<failure>");
8579 } else if (obj->IsUndefined()) {
8580 PrintF("<undefined>");
8581 } else if (obj->IsNull()) {
8582 PrintF("<null>");
8583 } else if (obj->IsTrue()) {
8584 PrintF("<true>");
8585 } else if (obj->IsFalse()) {
8586 PrintF("<false>");
8587 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008588 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008589 }
8590}
8591
8592
8593static int StackSize() {
8594 int n = 0;
8595 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8596 return n;
8597}
8598
8599
8600static void PrintTransition(Object* result) {
8601 // indentation
8602 { const int nmax = 80;
8603 int n = StackSize();
8604 if (n <= nmax)
8605 PrintF("%4d:%*s", n, n, "");
8606 else
8607 PrintF("%4d:%*s", n, nmax, "...");
8608 }
8609
8610 if (result == NULL) {
8611 // constructor calls
8612 JavaScriptFrameIterator it;
8613 JavaScriptFrame* frame = it.frame();
8614 if (frame->IsConstructor()) PrintF("new ");
8615 // function name
8616 Object* fun = frame->function();
8617 if (fun->IsJSFunction()) {
8618 PrintObject(JSFunction::cast(fun)->shared()->name());
8619 } else {
8620 PrintObject(fun);
8621 }
8622 // function arguments
8623 // (we are intentionally only printing the actually
8624 // supplied parameters, not all parameters required)
8625 PrintF("(this=");
8626 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008627 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008628 for (int i = 0; i < length; i++) {
8629 PrintF(", ");
8630 PrintObject(frame->GetParameter(i));
8631 }
8632 PrintF(") {\n");
8633
8634 } else {
8635 // function result
8636 PrintF("} -> ");
8637 PrintObject(result);
8638 PrintF("\n");
8639 }
8640}
8641
8642
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008643RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008644 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008645 NoHandleAllocation ha;
8646 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008647 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008648}
8649
8650
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008651RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008652 NoHandleAllocation ha;
8653 PrintTransition(args[0]);
8654 return args[0]; // return TOS
8655}
8656
8657
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008658RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008659 NoHandleAllocation ha;
8660 ASSERT(args.length() == 1);
8661
8662#ifdef DEBUG
8663 if (args[0]->IsString()) {
8664 // If we have a string, assume it's a code "marker"
8665 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008666 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008667 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008668 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8669 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008670 } else {
8671 PrintF("DebugPrint: ");
8672 }
8673 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008674 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008675 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008676 HeapObject::cast(args[0])->map()->Print();
8677 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008678#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008679 // ShortPrint is available in release mode. Print is not.
8680 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008681#endif
8682 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008683 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008684
8685 return args[0]; // return TOS
8686}
8687
8688
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008689RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008690 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008691 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008692 isolate->PrintStack();
8693 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008694}
8695
8696
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008697RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008698 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008699 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008700
8701 // According to ECMA-262, section 15.9.1, page 117, the precision of
8702 // the number in a Date object representing a particular instant in
8703 // time is milliseconds. Therefore, we floor the result of getting
8704 // the OS time.
8705 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008706 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008707}
8708
8709
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008710RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008711 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008712 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008713
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008714 CONVERT_ARG_CHECKED(String, str, 0);
8715 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008716
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008717 CONVERT_ARG_CHECKED(JSArray, output, 1);
8718 RUNTIME_ASSERT(output->HasFastElements());
8719
8720 AssertNoAllocation no_allocation;
8721
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008722 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008723 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8724 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008725 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008726 result = DateParser::Parse(str->ToAsciiVector(),
8727 output_array,
8728 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008729 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008730 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008731 result = DateParser::Parse(str->ToUC16Vector(),
8732 output_array,
8733 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008734 }
8735
8736 if (result) {
8737 return *output;
8738 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008739 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008740 }
8741}
8742
8743
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008744RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008745 NoHandleAllocation ha;
8746 ASSERT(args.length() == 1);
8747
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008748 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008749 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008750 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008751}
8752
8753
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008754RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008755 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008756 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008757
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008758 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008759}
8760
8761
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008762RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008763 NoHandleAllocation ha;
8764 ASSERT(args.length() == 1);
8765
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008766 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008767 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008768}
8769
8770
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008771RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008772 ASSERT(args.length() == 1);
8773 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008774 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008775 return JSGlobalObject::cast(global)->global_receiver();
8776}
8777
8778
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008779RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008780 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008781 ASSERT_EQ(1, args.length());
8782 CONVERT_ARG_CHECKED(String, source, 0);
8783
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008784 source = Handle<String>(source->TryFlattenGetString());
8785 // Optimized fast case where we only have ascii characters.
8786 Handle<Object> result;
8787 if (source->IsSeqAsciiString()) {
8788 result = JsonParser<true>::Parse(source);
8789 } else {
8790 result = JsonParser<false>::Parse(source);
8791 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008792 if (result.is_null()) {
8793 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008794 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008795 return Failure::Exception();
8796 }
8797 return *result;
8798}
8799
8800
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008801bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8802 Handle<Context> context) {
8803 if (context->allow_code_gen_from_strings()->IsFalse()) {
8804 // Check with callback if set.
8805 AllowCodeGenerationFromStringsCallback callback =
8806 isolate->allow_code_gen_callback();
8807 if (callback == NULL) {
8808 // No callback set and code generation disallowed.
8809 return false;
8810 } else {
8811 // Callback set. Let it decide if code generation is allowed.
8812 VMState state(isolate, EXTERNAL);
8813 return callback(v8::Utils::ToLocal(context));
8814 }
8815 }
8816 return true;
8817}
8818
8819
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008820RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008821 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008822 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008823 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008824
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008825 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008826 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008827
8828 // Check if global context allows code generation from
8829 // strings. Throw an exception if it doesn't.
8830 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8831 return isolate->Throw(*isolate->factory()->NewError(
8832 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8833 }
8834
8835 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008836 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8837 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008838 true,
8839 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008840 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008841 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008842 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8843 context,
8844 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008845 return *fun;
8846}
8847
8848
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008849static ObjectPair CompileGlobalEval(Isolate* isolate,
8850 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008851 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008852 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008853 Handle<Context> context = Handle<Context>(isolate->context());
8854 Handle<Context> global_context = Handle<Context>(context->global_context());
8855
8856 // Check if global context allows code generation from
8857 // strings. Throw an exception if it doesn't.
8858 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8859 isolate->Throw(*isolate->factory()->NewError(
8860 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8861 return MakePair(Failure::Exception(), NULL);
8862 }
8863
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008864 // Deal with a normal eval call with a string argument. Compile it
8865 // and return the compiled function bound in the local context.
8866 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8867 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008868 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008869 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008870 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008871 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008872 Handle<JSFunction> compiled =
8873 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008874 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008875 return MakePair(*compiled, *receiver);
8876}
8877
8878
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008879RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008880 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008881
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008882 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008883 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008884 Handle<Object> receiver; // Will be overwritten.
8885
8886 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008887 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008888#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008889 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008890 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008891 StackFrameLocator locator;
8892 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008893 ASSERT(Context::cast(frame->context()) == *context);
8894#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008895
8896 // Find where the 'eval' symbol is bound. It is unaliased only if
8897 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008898 int index = -1;
8899 PropertyAttributes attributes = ABSENT;
8900 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008901 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8902 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008903 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008904 // Stop search when eval is found or when the global context is
8905 // reached.
8906 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008907 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008908 }
8909
iposva@chromium.org245aa852009-02-10 00:49:54 +00008910 // If eval could not be resolved, it has been deleted and we need to
8911 // throw a reference error.
8912 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008913 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008914 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008915 isolate->factory()->NewReferenceError("not_defined",
8916 HandleVector(&name, 1));
8917 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008918 }
8919
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008920 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008921 // 'eval' is not bound in the global context. Just call the function
8922 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00008923 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008924 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008925 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008926 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008927 }
8928
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008929 // 'eval' is bound in the global context, but it may have been overwritten.
8930 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008931 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008932 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008933 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008934 }
8935
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008936 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008937 return CompileGlobalEval(isolate,
8938 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008939 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008940 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008941}
8942
8943
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008944RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008945 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008946
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008947 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008948 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008949
8950 // 'eval' is bound in the global context, but it may have been overwritten.
8951 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008952 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008953 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008954 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008955 }
8956
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008957 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008958 return CompileGlobalEval(isolate,
8959 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008960 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008961 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008962}
8963
8964
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008965RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008966 // This utility adjusts the property attributes for newly created Function
8967 // object ("new Function(...)") by changing the map.
8968 // All it does is changing the prototype property to enumerable
8969 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008970 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008971 ASSERT(args.length() == 1);
8972 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008973
8974 Handle<Map> map = func->shared()->strict_mode()
8975 ? isolate->strict_mode_function_instance_map()
8976 : isolate->function_instance_map();
8977
8978 ASSERT(func->map()->instance_type() == map->instance_type());
8979 ASSERT(func->map()->instance_size() == map->instance_size());
8980 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008981 return *func;
8982}
8983
8984
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008985RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008986 // Allocate a block of memory in NewSpace (filled with a filler).
8987 // Use as fallback for allocation in generated code when NewSpace
8988 // is full.
8989 ASSERT(args.length() == 1);
8990 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8991 int size = size_smi->value();
8992 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8993 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008994 Heap* heap = isolate->heap();
8995 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008996 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008997 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008998 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008999 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009000 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009001 }
9002 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009003 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009004}
9005
9006
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009007// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009008// array. Returns true if the element was pushed on the stack and
9009// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009010RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009011 ASSERT(args.length() == 2);
9012 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009013 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009014 RUNTIME_ASSERT(array->HasFastElements());
9015 int length = Smi::cast(array->length())->value();
9016 FixedArray* elements = FixedArray::cast(array->elements());
9017 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009018 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009019 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009020 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009021 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009022 { MaybeObject* maybe_obj =
9023 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009024 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9025 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009026 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009027}
9028
9029
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009030/**
9031 * A simple visitor visits every element of Array's.
9032 * The backend storage can be a fixed array for fast elements case,
9033 * or a dictionary for sparse array. Since Dictionary is a subtype
9034 * of FixedArray, the class can be used by both fast and slow cases.
9035 * The second parameter of the constructor, fast_elements, specifies
9036 * whether the storage is a FixedArray or Dictionary.
9037 *
9038 * An index limit is used to deal with the situation that a result array
9039 * length overflows 32-bit non-negative integer.
9040 */
9041class ArrayConcatVisitor {
9042 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009043 ArrayConcatVisitor(Isolate* isolate,
9044 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009045 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009046 isolate_(isolate),
9047 storage_(Handle<FixedArray>::cast(
9048 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009049 index_offset_(0u),
9050 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009051
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009052 ~ArrayConcatVisitor() {
9053 clear_storage();
9054 }
9055
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009056 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009057 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009058 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009059
9060 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009061 if (index < static_cast<uint32_t>(storage_->length())) {
9062 storage_->set(index, *elm);
9063 return;
9064 }
9065 // Our initial estimate of length was foiled, possibly by
9066 // getters on the arrays increasing the length of later arrays
9067 // during iteration.
9068 // This shouldn't happen in anything but pathological cases.
9069 SetDictionaryMode(index);
9070 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009071 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009072 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009073 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009074 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009075 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009076 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009077 // Dictionary needed to grow.
9078 clear_storage();
9079 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009080 }
9081}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009082
9083 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009084 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9085 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009086 } else {
9087 index_offset_ += delta;
9088 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009089 }
9090
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009091 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009092 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009093 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009094 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009095 Handle<Map> map;
9096 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009097 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009098 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009099 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009100 }
9101 array->set_map(*map);
9102 array->set_length(*length);
9103 array->set_elements(*storage_);
9104 return array;
9105 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009106
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009107 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009108 // Convert storage to dictionary mode.
9109 void SetDictionaryMode(uint32_t index) {
9110 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009111 Handle<FixedArray> current_storage(*storage_);
9112 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009113 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009114 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9115 for (uint32_t i = 0; i < current_length; i++) {
9116 HandleScope loop_scope;
9117 Handle<Object> element(current_storage->get(i));
9118 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009119 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009120 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009121 if (!new_storage.is_identical_to(slow_storage)) {
9122 slow_storage = loop_scope.CloseAndEscape(new_storage);
9123 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009124 }
9125 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009126 clear_storage();
9127 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009128 fast_elements_ = false;
9129 }
9130
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009131 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009132 isolate_->global_handles()->Destroy(
9133 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009134 }
9135
9136 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009137 storage_ = Handle<FixedArray>::cast(
9138 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009139 }
9140
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009141 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009142 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009143 // Index after last seen index. Always less than or equal to
9144 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009145 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009146 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009147};
9148
9149
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009150static uint32_t EstimateElementCount(Handle<JSArray> array) {
9151 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9152 int element_count = 0;
9153 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009154 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009155 // Fast elements can't have lengths that are not representable by
9156 // a 32-bit signed integer.
9157 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9158 int fast_length = static_cast<int>(length);
9159 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9160 for (int i = 0; i < fast_length; i++) {
9161 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009162 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009163 break;
9164 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009165 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009166 Handle<NumberDictionary> dictionary(
9167 NumberDictionary::cast(array->elements()));
9168 int capacity = dictionary->Capacity();
9169 for (int i = 0; i < capacity; i++) {
9170 Handle<Object> key(dictionary->KeyAt(i));
9171 if (dictionary->IsKey(*key)) {
9172 element_count++;
9173 }
9174 }
9175 break;
9176 }
9177 default:
9178 // External arrays are always dense.
9179 return length;
9180 }
9181 // As an estimate, we assume that the prototype doesn't contain any
9182 // inherited elements.
9183 return element_count;
9184}
9185
9186
9187
9188template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009189static void IterateExternalArrayElements(Isolate* isolate,
9190 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009191 bool elements_are_ints,
9192 bool elements_are_guaranteed_smis,
9193 ArrayConcatVisitor* visitor) {
9194 Handle<ExternalArrayClass> array(
9195 ExternalArrayClass::cast(receiver->elements()));
9196 uint32_t len = static_cast<uint32_t>(array->length());
9197
9198 ASSERT(visitor != NULL);
9199 if (elements_are_ints) {
9200 if (elements_are_guaranteed_smis) {
9201 for (uint32_t j = 0; j < len; j++) {
9202 HandleScope loop_scope;
9203 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
9204 visitor->visit(j, e);
9205 }
9206 } else {
9207 for (uint32_t j = 0; j < len; j++) {
9208 HandleScope loop_scope;
9209 int64_t val = static_cast<int64_t>(array->get(j));
9210 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9211 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9212 visitor->visit(j, e);
9213 } else {
9214 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009215 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009216 visitor->visit(j, e);
9217 }
9218 }
9219 }
9220 } else {
9221 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009222 HandleScope loop_scope(isolate);
9223 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009224 visitor->visit(j, e);
9225 }
9226 }
9227}
9228
9229
9230// Used for sorting indices in a List<uint32_t>.
9231static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9232 uint32_t a = *ap;
9233 uint32_t b = *bp;
9234 return (a == b) ? 0 : (a < b) ? -1 : 1;
9235}
9236
9237
9238static void CollectElementIndices(Handle<JSObject> object,
9239 uint32_t range,
9240 List<uint32_t>* indices) {
9241 JSObject::ElementsKind kind = object->GetElementsKind();
9242 switch (kind) {
9243 case JSObject::FAST_ELEMENTS: {
9244 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9245 uint32_t length = static_cast<uint32_t>(elements->length());
9246 if (range < length) length = range;
9247 for (uint32_t i = 0; i < length; i++) {
9248 if (!elements->get(i)->IsTheHole()) {
9249 indices->Add(i);
9250 }
9251 }
9252 break;
9253 }
9254 case JSObject::DICTIONARY_ELEMENTS: {
9255 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009256 uint32_t capacity = dict->Capacity();
9257 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009258 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009259 Handle<Object> k(dict->KeyAt(j));
9260 if (dict->IsKey(*k)) {
9261 ASSERT(k->IsNumber());
9262 uint32_t index = static_cast<uint32_t>(k->Number());
9263 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009264 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009265 }
9266 }
9267 }
9268 break;
9269 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009270 default: {
9271 int dense_elements_length;
9272 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009273 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009274 dense_elements_length =
9275 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009276 break;
9277 }
9278 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009279 dense_elements_length =
9280 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009281 break;
9282 }
9283 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009284 dense_elements_length =
9285 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009286 break;
9287 }
9288 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009289 dense_elements_length =
9290 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009291 break;
9292 }
9293 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009294 dense_elements_length =
9295 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009296 break;
9297 }
9298 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009299 dense_elements_length =
9300 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009301 break;
9302 }
9303 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009304 dense_elements_length =
9305 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009306 break;
9307 }
9308 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009309 dense_elements_length =
9310 ExternalFloatArray::cast(object->elements())->length();
9311 break;
9312 }
9313 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9314 dense_elements_length =
9315 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009316 break;
9317 }
9318 default:
9319 UNREACHABLE();
9320 dense_elements_length = 0;
9321 break;
9322 }
9323 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9324 if (range <= length) {
9325 length = range;
9326 // We will add all indices, so we might as well clear it first
9327 // and avoid duplicates.
9328 indices->Clear();
9329 }
9330 for (uint32_t i = 0; i < length; i++) {
9331 indices->Add(i);
9332 }
9333 if (length == range) return; // All indices accounted for already.
9334 break;
9335 }
9336 }
9337
9338 Handle<Object> prototype(object->GetPrototype());
9339 if (prototype->IsJSObject()) {
9340 // The prototype will usually have no inherited element indices,
9341 // but we have to check.
9342 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9343 }
9344}
9345
9346
9347/**
9348 * A helper function that visits elements of a JSArray in numerical
9349 * order.
9350 *
9351 * The visitor argument called for each existing element in the array
9352 * with the element index and the element's value.
9353 * Afterwards it increments the base-index of the visitor by the array
9354 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009355 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009356 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009357static bool IterateElements(Isolate* isolate,
9358 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009359 ArrayConcatVisitor* visitor) {
9360 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9361 switch (receiver->GetElementsKind()) {
9362 case JSObject::FAST_ELEMENTS: {
9363 // Run through the elements FixedArray and use HasElement and GetElement
9364 // to check the prototype for missing elements.
9365 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9366 int fast_length = static_cast<int>(length);
9367 ASSERT(fast_length <= elements->length());
9368 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009369 HandleScope loop_scope(isolate);
9370 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009371 if (!element_value->IsTheHole()) {
9372 visitor->visit(j, element_value);
9373 } else if (receiver->HasElement(j)) {
9374 // Call GetElement on receiver, not its prototype, or getters won't
9375 // have the correct receiver.
9376 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009377 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009378 visitor->visit(j, element_value);
9379 }
9380 }
9381 break;
9382 }
9383 case JSObject::DICTIONARY_ELEMENTS: {
9384 Handle<NumberDictionary> dict(receiver->element_dictionary());
9385 List<uint32_t> indices(dict->Capacity() / 2);
9386 // Collect all indices in the object and the prototypes less
9387 // than length. This might introduce duplicates in the indices list.
9388 CollectElementIndices(receiver, length, &indices);
9389 indices.Sort(&compareUInt32);
9390 int j = 0;
9391 int n = indices.length();
9392 while (j < n) {
9393 HandleScope loop_scope;
9394 uint32_t index = indices[j];
9395 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009396 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009397 visitor->visit(index, element);
9398 // Skip to next different index (i.e., omit duplicates).
9399 do {
9400 j++;
9401 } while (j < n && indices[j] == index);
9402 }
9403 break;
9404 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009405 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
9406 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9407 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009408 for (uint32_t j = 0; j < length; j++) {
9409 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
9410 visitor->visit(j, e);
9411 }
9412 break;
9413 }
9414 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
9415 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009416 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009417 break;
9418 }
9419 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9420 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009421 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009422 break;
9423 }
9424 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
9425 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009426 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009427 break;
9428 }
9429 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9430 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009431 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009432 break;
9433 }
9434 case JSObject::EXTERNAL_INT_ELEMENTS: {
9435 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009436 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009437 break;
9438 }
9439 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9440 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009441 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009442 break;
9443 }
9444 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9445 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009446 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009447 break;
9448 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009449 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9450 IterateExternalArrayElements<ExternalDoubleArray, double>(
9451 isolate, receiver, false, false, visitor);
9452 break;
9453 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009454 default:
9455 UNREACHABLE();
9456 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009457 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009458 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009459 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009460}
9461
9462
9463/**
9464 * Array::concat implementation.
9465 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009466 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009467 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009468 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009469RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009470 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009471 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009472
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009473 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9474 int argument_count = static_cast<int>(arguments->length()->Number());
9475 RUNTIME_ASSERT(arguments->HasFastElements());
9476 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009477
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009478 // Pass 1: estimate the length and number of elements of the result.
9479 // The actual length can be larger if any of the arguments have getters
9480 // that mutate other arguments (but will otherwise be precise).
9481 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009482
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009483 uint32_t estimate_result_length = 0;
9484 uint32_t estimate_nof_elements = 0;
9485 {
9486 for (int i = 0; i < argument_count; i++) {
9487 HandleScope loop_scope;
9488 Handle<Object> obj(elements->get(i));
9489 uint32_t length_estimate;
9490 uint32_t element_estimate;
9491 if (obj->IsJSArray()) {
9492 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9493 length_estimate =
9494 static_cast<uint32_t>(array->length()->Number());
9495 element_estimate =
9496 EstimateElementCount(array);
9497 } else {
9498 length_estimate = 1;
9499 element_estimate = 1;
9500 }
9501 // Avoid overflows by capping at kMaxElementCount.
9502 if (JSObject::kMaxElementCount - estimate_result_length <
9503 length_estimate) {
9504 estimate_result_length = JSObject::kMaxElementCount;
9505 } else {
9506 estimate_result_length += length_estimate;
9507 }
9508 if (JSObject::kMaxElementCount - estimate_nof_elements <
9509 element_estimate) {
9510 estimate_nof_elements = JSObject::kMaxElementCount;
9511 } else {
9512 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009513 }
9514 }
9515 }
9516
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009517 // If estimated number of elements is more than half of length, a
9518 // fixed array (fast case) is more time and space-efficient than a
9519 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009520 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009521
9522 Handle<FixedArray> storage;
9523 if (fast_case) {
9524 // The backing storage array must have non-existing elements to
9525 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009526 storage = isolate->factory()->NewFixedArrayWithHoles(
9527 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009528 } else {
9529 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9530 uint32_t at_least_space_for = estimate_nof_elements +
9531 (estimate_nof_elements >> 2);
9532 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009533 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009534 }
9535
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009536 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009537
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009538 for (int i = 0; i < argument_count; i++) {
9539 Handle<Object> obj(elements->get(i));
9540 if (obj->IsJSArray()) {
9541 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009542 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009543 return Failure::Exception();
9544 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009545 } else {
9546 visitor.visit(0, obj);
9547 visitor.increase_index_offset(1);
9548 }
9549 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009550
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009551 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009552}
9553
9554
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009555// This will not allocate (flatten the string), but it may run
9556// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009557RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009558 NoHandleAllocation ha;
9559 ASSERT(args.length() == 1);
9560
9561 CONVERT_CHECKED(String, string, args[0]);
9562 StringInputBuffer buffer(string);
9563 while (buffer.has_more()) {
9564 uint16_t character = buffer.GetNext();
9565 PrintF("%c", character);
9566 }
9567 return string;
9568}
9569
ager@chromium.org5ec48922009-05-05 07:25:34 +00009570// Moves all own elements of an object, that are below a limit, to positions
9571// starting at zero. All undefined values are placed after non-undefined values,
9572// and are followed by non-existing element. Does not change the length
9573// property.
9574// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009575RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009576 ASSERT(args.length() == 2);
9577 CONVERT_CHECKED(JSObject, object, args[0]);
9578 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9579 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009580}
9581
9582
9583// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009584RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009585 ASSERT(args.length() == 2);
9586 CONVERT_CHECKED(JSArray, from, args[0]);
9587 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009588 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009589 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009590 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9591 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009592 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009593 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009594 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009595 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009596 Object* new_map;
9597 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009598 to->set_map(Map::cast(new_map));
9599 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009600 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009601 Object* obj;
9602 { MaybeObject* maybe_obj = from->ResetElements();
9603 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9604 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009605 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009606 return to;
9607}
9608
9609
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009610// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009611RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009612 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009613 CONVERT_CHECKED(JSObject, object, args[0]);
9614 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009615 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009616 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009617 } else if (object->IsJSArray()) {
9618 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009619 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009620 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009621 }
9622}
9623
9624
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009625RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009626 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009627
9628 ASSERT_EQ(3, args.length());
9629
ager@chromium.orgac091b72010-05-05 07:34:42 +00009630 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009631 Handle<Object> key1 = args.at<Object>(1);
9632 Handle<Object> key2 = args.at<Object>(2);
9633
9634 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009635 if (!key1->ToArrayIndex(&index1)
9636 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009637 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009638 }
9639
ager@chromium.orgac091b72010-05-05 07:34:42 +00009640 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9641 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009642 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009643 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009644 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009645
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009646 RETURN_IF_EMPTY_HANDLE(isolate,
9647 SetElement(jsobject, index1, tmp2, kStrictMode));
9648 RETURN_IF_EMPTY_HANDLE(isolate,
9649 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009650
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009651 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009652}
9653
9654
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009655// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009656// might have elements. Can either return keys (positive integers) or
9657// intervals (pair of a negative integer (-start-1) followed by a
9658// positive (length)) or undefined values.
9659// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009660RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009661 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009662 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009663 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009664 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009665 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009666 // Create an array and get all the keys into it, then remove all the
9667 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009668 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009669 int keys_length = keys->length();
9670 for (int i = 0; i < keys_length; i++) {
9671 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009672 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009673 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009674 // Zap invalid keys.
9675 keys->set_undefined(i);
9676 }
9677 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009678 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009679 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009680 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009681 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009682 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009683 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009684 uint32_t actual_length =
9685 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009686 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009687 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009688 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009689 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009690 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009691 }
9692}
9693
9694
9695// DefineAccessor takes an optional final argument which is the
9696// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9697// to the way accessors are implemented, it is set for both the getter
9698// and setter on the first call to DefineAccessor and ignored on
9699// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009700RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009701 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9702 // Compute attributes.
9703 PropertyAttributes attributes = NONE;
9704 if (args.length() == 5) {
9705 CONVERT_CHECKED(Smi, attrs, args[4]);
9706 int value = attrs->value();
9707 // Only attribute bits should be set.
9708 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9709 attributes = static_cast<PropertyAttributes>(value);
9710 }
9711
9712 CONVERT_CHECKED(JSObject, obj, args[0]);
9713 CONVERT_CHECKED(String, name, args[1]);
9714 CONVERT_CHECKED(Smi, flag, args[2]);
9715 CONVERT_CHECKED(JSFunction, fun, args[3]);
9716 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9717}
9718
9719
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009720RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009721 ASSERT(args.length() == 3);
9722 CONVERT_CHECKED(JSObject, obj, args[0]);
9723 CONVERT_CHECKED(String, name, args[1]);
9724 CONVERT_CHECKED(Smi, flag, args[2]);
9725 return obj->LookupAccessor(name, flag->value() == 0);
9726}
9727
9728
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009729#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009730RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009731 ASSERT(args.length() == 0);
9732 return Execution::DebugBreakHelper();
9733}
9734
9735
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009736// Helper functions for wrapping and unwrapping stack frame ids.
9737static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009738 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009739 return Smi::FromInt(id >> 2);
9740}
9741
9742
9743static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9744 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9745}
9746
9747
9748// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009749// args[0]: debug event listener function to set or null or undefined for
9750// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009751// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009752RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009753 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009754 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9755 args[0]->IsUndefined() ||
9756 args[0]->IsNull());
9757 Handle<Object> callback = args.at<Object>(0);
9758 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009759 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009760
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009761 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009762}
9763
9764
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009765RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009766 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009767 isolate->stack_guard()->DebugBreak();
9768 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009769}
9770
9771
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009772static MaybeObject* DebugLookupResultValue(Heap* heap,
9773 Object* receiver,
9774 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009775 LookupResult* result,
9776 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009777 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009778 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009779 case NORMAL:
9780 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009781 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009782 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009783 }
9784 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009785 case FIELD:
9786 value =
9787 JSObject::cast(
9788 result->holder())->FastPropertyAt(result->GetFieldIndex());
9789 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009790 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009791 }
9792 return value;
9793 case CONSTANT_FUNCTION:
9794 return result->GetConstantFunction();
9795 case CALLBACKS: {
9796 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009797 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009798 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009799 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009800 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009801 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009802 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009803 maybe_value = heap->isolate()->pending_exception();
9804 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009805 if (caught_exception != NULL) {
9806 *caught_exception = true;
9807 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009808 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009809 }
9810 return value;
9811 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009812 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009813 }
9814 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009815 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009816 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009817 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009818 case CONSTANT_TRANSITION:
9819 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009820 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009821 default:
9822 UNREACHABLE();
9823 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009824 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009825 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009826}
9827
9828
ager@chromium.org32912102009-01-16 10:38:43 +00009829// Get debugger related details for an object property.
9830// args[0]: object holding property
9831// args[1]: name of the property
9832//
9833// The array returned contains the following information:
9834// 0: Property value
9835// 1: Property details
9836// 2: Property value is exception
9837// 3: Getter function if defined
9838// 4: Setter function if defined
9839// Items 2-4 are only filled if the property has either a getter or a setter
9840// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009841RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009842 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009843
9844 ASSERT(args.length() == 2);
9845
9846 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9847 CONVERT_ARG_CHECKED(String, name, 1);
9848
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009849 // Make sure to set the current context to the context before the debugger was
9850 // entered (if the debugger is entered). The reason for switching context here
9851 // is that for some property lookups (accessors and interceptors) callbacks
9852 // into the embedding application can occour, and the embedding application
9853 // could have the assumption that its own global context is the current
9854 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009855 SaveContext save(isolate);
9856 if (isolate->debug()->InDebugger()) {
9857 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009858 }
9859
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009860 // Skip the global proxy as it has no properties and always delegates to the
9861 // real global object.
9862 if (obj->IsJSGlobalProxy()) {
9863 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9864 }
9865
9866
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009867 // Check if the name is trivially convertible to an index and get the element
9868 // if so.
9869 uint32_t index;
9870 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009871 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009872 Object* element_or_char;
9873 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009874 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009875 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9876 return maybe_element_or_char;
9877 }
9878 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009879 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009880 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009881 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009882 }
9883
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009884 // Find the number of objects making up this.
9885 int length = LocalPrototypeChainLength(*obj);
9886
9887 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009888 Handle<JSObject> jsproto = obj;
9889 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009890 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009891 jsproto->LocalLookup(*name, &result);
9892 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009893 // LookupResult is not GC safe as it holds raw object pointers.
9894 // GC can happen later in this code so put the required fields into
9895 // local variables using handles when required for later use.
9896 PropertyType result_type = result.type();
9897 Handle<Object> result_callback_obj;
9898 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009899 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9900 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009901 }
9902 Smi* property_details = result.GetPropertyDetails().AsSmi();
9903 // DebugLookupResultValue can cause GC so details from LookupResult needs
9904 // to be copied to handles before this.
9905 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009906 Object* raw_value;
9907 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009908 DebugLookupResultValue(isolate->heap(), *obj, *name,
9909 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009910 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9911 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009912 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009913
9914 // If the callback object is a fixed array then it contains JavaScript
9915 // getter and/or setter.
9916 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9917 result_callback_obj->IsFixedArray();
9918 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009919 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009920 details->set(0, *value);
9921 details->set(1, property_details);
9922 if (hasJavaScriptAccessors) {
9923 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009924 caught_exception ? isolate->heap()->true_value()
9925 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009926 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9927 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9928 }
9929
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009930 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009931 }
9932 if (i < length - 1) {
9933 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9934 }
9935 }
9936
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009937 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009938}
9939
9940
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009941RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009942 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009943
9944 ASSERT(args.length() == 2);
9945
9946 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9947 CONVERT_ARG_CHECKED(String, name, 1);
9948
9949 LookupResult result;
9950 obj->Lookup(*name, &result);
9951 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009952 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009953 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009954 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009955}
9956
9957
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009958// Return the property type calculated from the property details.
9959// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009960RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009961 ASSERT(args.length() == 1);
9962 CONVERT_CHECKED(Smi, details, args[0]);
9963 PropertyType type = PropertyDetails(details).type();
9964 return Smi::FromInt(static_cast<int>(type));
9965}
9966
9967
9968// Return the property attribute calculated from the property details.
9969// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009970RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009971 ASSERT(args.length() == 1);
9972 CONVERT_CHECKED(Smi, details, args[0]);
9973 PropertyAttributes attributes = PropertyDetails(details).attributes();
9974 return Smi::FromInt(static_cast<int>(attributes));
9975}
9976
9977
9978// Return the property insertion index calculated from the property details.
9979// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009980RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009981 ASSERT(args.length() == 1);
9982 CONVERT_CHECKED(Smi, details, args[0]);
9983 int index = PropertyDetails(details).index();
9984 return Smi::FromInt(index);
9985}
9986
9987
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009988// Return property value from named interceptor.
9989// args[0]: object
9990// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009991RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009992 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009993 ASSERT(args.length() == 2);
9994 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9995 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9996 CONVERT_ARG_CHECKED(String, name, 1);
9997
9998 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009999 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010000}
10001
10002
10003// Return element value from indexed interceptor.
10004// args[0]: object
10005// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010006RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010007 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010008 ASSERT(args.length() == 2);
10009 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10010 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10011 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10012
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010013 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010014}
10015
10016
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010017RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010018 ASSERT(args.length() >= 1);
10019 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010020 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010021 if (isolate->debug()->break_id() == 0 ||
10022 break_id != isolate->debug()->break_id()) {
10023 return isolate->Throw(
10024 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010025 }
10026
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010027 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010028}
10029
10030
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010031RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010032 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010033 ASSERT(args.length() == 1);
10034
10035 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010036 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010037 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10038 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010039 if (!maybe_result->ToObject(&result)) return maybe_result;
10040 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010041
10042 // Count all frames which are relevant to debugging stack trace.
10043 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010044 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010045 if (id == StackFrame::NO_ID) {
10046 // If there is no JavaScript stack frame count is 0.
10047 return Smi::FromInt(0);
10048 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010049
10050 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10051 n += it.frame()->GetInlineCount();
10052 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010053 return Smi::FromInt(n);
10054}
10055
10056
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010057class FrameInspector {
10058 public:
10059 FrameInspector(JavaScriptFrame* frame,
10060 int inlined_frame_index,
10061 Isolate* isolate)
10062 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10063 // Calculate the deoptimized frame.
10064 if (frame->is_optimized()) {
10065 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10066 frame, inlined_frame_index, isolate);
10067 }
10068 has_adapted_arguments_ = frame_->has_adapted_arguments();
10069 is_optimized_ = frame_->is_optimized();
10070 }
10071
10072 ~FrameInspector() {
10073 // Get rid of the calculated deoptimized frame if any.
10074 if (deoptimized_frame_ != NULL) {
10075 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10076 isolate_);
10077 }
10078 }
10079
10080 int GetParametersCount() {
10081 return is_optimized_
10082 ? deoptimized_frame_->parameters_count()
10083 : frame_->ComputeParametersCount();
10084 }
10085 int expression_count() { return deoptimized_frame_->expression_count(); }
10086 Object* GetFunction() {
10087 return is_optimized_
10088 ? deoptimized_frame_->GetFunction()
10089 : frame_->function();
10090 }
10091 Object* GetParameter(int index) {
10092 return is_optimized_
10093 ? deoptimized_frame_->GetParameter(index)
10094 : frame_->GetParameter(index);
10095 }
10096 Object* GetExpression(int index) {
10097 return is_optimized_
10098 ? deoptimized_frame_->GetExpression(index)
10099 : frame_->GetExpression(index);
10100 }
10101
10102 // To inspect all the provided arguments the frame might need to be
10103 // replaced with the arguments frame.
10104 void SetArgumentsFrame(JavaScriptFrame* frame) {
10105 ASSERT(has_adapted_arguments_);
10106 frame_ = frame;
10107 is_optimized_ = frame_->is_optimized();
10108 ASSERT(!is_optimized_);
10109 }
10110
10111 private:
10112 JavaScriptFrame* frame_;
10113 DeoptimizedFrameInfo* deoptimized_frame_;
10114 Isolate* isolate_;
10115 bool is_optimized_;
10116 bool has_adapted_arguments_;
10117
10118 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10119};
10120
10121
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010122static const int kFrameDetailsFrameIdIndex = 0;
10123static const int kFrameDetailsReceiverIndex = 1;
10124static const int kFrameDetailsFunctionIndex = 2;
10125static const int kFrameDetailsArgumentCountIndex = 3;
10126static const int kFrameDetailsLocalCountIndex = 4;
10127static const int kFrameDetailsSourcePositionIndex = 5;
10128static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010129static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010130static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010131static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010132
10133// Return an array with frame details
10134// args[0]: number: break id
10135// args[1]: number: frame index
10136//
10137// The array returned contains the following information:
10138// 0: Frame id
10139// 1: Receiver
10140// 2: Function
10141// 3: Argument count
10142// 4: Local count
10143// 5: Source position
10144// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010145// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010146// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010147// Arguments name, value
10148// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010149// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010150RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010151 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010152 ASSERT(args.length() == 2);
10153
10154 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010155 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010156 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10157 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010158 if (!maybe_check->ToObject(&check)) return maybe_check;
10159 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010160 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010161 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010162
10163 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010164 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010165 if (id == StackFrame::NO_ID) {
10166 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010167 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010168 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010169
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010170 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010171
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010172 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010173 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010174 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010175 if (index < count + it.frame()->GetInlineCount()) break;
10176 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010177 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010178 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010179
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010180 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010181 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010182 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010183 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010184 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010185
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010186 // Traverse the saved contexts chain to find the active context for the
10187 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010188 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010189 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010190 save = save->prev();
10191 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010192 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010193
10194 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010195 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010196
10197 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010198 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010199 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010200
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010201 // Check for constructor frame. Inlined frames cannot be construct calls.
10202 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010203 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010204 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010205
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010206 // Get scope info and read from it for local variable information.
10207 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010208 Handle<SharedFunctionInfo> shared(function->shared());
10209 Handle<SerializedScopeInfo> scope_info(shared->scope_info());
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010210 ASSERT(*scope_info != SerializedScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010211 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010212
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010213 // Get the locals names and values into a temporary array.
10214 //
10215 // TODO(1240907): Hide compiler-introduced stack variables
10216 // (e.g. .result)? For users of the debugger, they will probably be
10217 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010218 Handle<FixedArray> locals =
10219 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010220
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010221 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010222 int i = 0;
10223 for (; i < info.number_of_stack_slots(); ++i) {
10224 // Use the value from the stack.
10225 locals->set(i * 2, *info.LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010226 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010227 }
10228 if (i < info.NumberOfLocals()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010229 // Get the context containing declarations.
10230 Handle<Context> context(
10231 Context::cast(it.frame()->context())->declaration_context());
10232 for (; i < info.NumberOfLocals(); ++i) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010233 Handle<String> name = info.LocalName(i);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010234 locals->set(i * 2, *name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010235 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010236 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010237 }
10238 }
10239
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010240 // Check whether this frame is positioned at return. If not top
10241 // frame or if the frame is optimized it cannot be at a return.
10242 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010243 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010244 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010245 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010246
10247 // If positioned just before return find the value to be returned and add it
10248 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010249 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010250 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010251 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010252 Address internal_frame_sp = NULL;
10253 while (!it2.done()) {
10254 if (it2.frame()->is_internal()) {
10255 internal_frame_sp = it2.frame()->sp();
10256 } else {
10257 if (it2.frame()->is_java_script()) {
10258 if (it2.frame()->id() == it.frame()->id()) {
10259 // The internal frame just before the JavaScript frame contains the
10260 // value to return on top. A debug break at return will create an
10261 // internal frame to store the return value (eax/rax/r0) before
10262 // entering the debug break exit frame.
10263 if (internal_frame_sp != NULL) {
10264 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010265 Handle<Object>(Memory::Object_at(internal_frame_sp),
10266 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010267 break;
10268 }
10269 }
10270 }
10271
10272 // Indicate that the previous frame was not an internal frame.
10273 internal_frame_sp = NULL;
10274 }
10275 it2.Advance();
10276 }
10277 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010278
10279 // Now advance to the arguments adapter frame (if any). It contains all
10280 // the provided parameters whereas the function frame always have the number
10281 // of arguments matching the functions parameters. The rest of the
10282 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010283 if (it.frame()->has_adapted_arguments()) {
10284 it.AdvanceToArgumentsFrame();
10285 frame_inspector.SetArgumentsFrame(it.frame());
10286 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010287
10288 // Find the number of arguments to fill. At least fill the number of
10289 // parameters for the function and fill more if more parameters are provided.
10290 int argument_count = info.number_of_parameters();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010291 if (argument_count < frame_inspector.GetParametersCount()) {
10292 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010293 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010294#ifdef DEBUG
10295 if (it.frame()->is_optimized()) {
10296 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10297 }
10298#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010299
10300 // Calculate the size of the result.
10301 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010302 2 * (argument_count + info.NumberOfLocals()) +
10303 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010304 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010305
10306 // Add the frame id.
10307 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10308
10309 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010310 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010311
10312 // Add the arguments count.
10313 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10314
10315 // Add the locals count
10316 details->set(kFrameDetailsLocalCountIndex,
10317 Smi::FromInt(info.NumberOfLocals()));
10318
10319 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010320 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010321 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10322 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010323 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010324 }
10325
10326 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010327 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010328
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010329 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010330 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010331
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010332 // Add flags to indicate information on whether this frame is
10333 // bit 0: invoked in the debugger context.
10334 // bit 1: optimized frame.
10335 // bit 2: inlined in optimized frame
10336 int flags = 0;
10337 if (*save->context() == *isolate->debug()->debug_context()) {
10338 flags |= 1 << 0;
10339 }
10340 if (it.frame()->is_optimized()) {
10341 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010342 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010343 }
10344 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010345
10346 // Fill the dynamic part.
10347 int details_index = kFrameDetailsFirstDynamicIndex;
10348
10349 // Add arguments name and value.
10350 for (int i = 0; i < argument_count; i++) {
10351 // Name of the argument.
10352 if (i < info.number_of_parameters()) {
10353 details->set(details_index++, *info.parameter_name(i));
10354 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010355 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010356 }
10357
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010358 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010359 if (i < it.frame()->ComputeParametersCount()) {
10360 // Get the value from the stack.
10361 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010362 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010363 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010364 }
10365 }
10366
10367 // Add locals name and value from the temporary copy from the function frame.
10368 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10369 details->set(details_index++, locals->get(i));
10370 }
10371
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010372 // Add the value being returned.
10373 if (at_return) {
10374 details->set(details_index++, *return_value);
10375 }
10376
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010377 // Add the receiver (same as in function frame).
10378 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10379 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010380 Handle<Object> receiver(it.frame()->receiver(), isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010381 if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
10382 // If the receiver is not a JSObject and the function is not a
10383 // builtin or strict-mode we have hit an optimization where a
10384 // value object is not converted into a wrapped JS objects. To
10385 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010386 // by creating correct wrapper object based on the calling frame's
10387 // global context.
10388 it.Advance();
10389 Handle<Context> calling_frames_global_context(
10390 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010391 receiver =
10392 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010393 }
10394 details->set(kFrameDetailsReceiverIndex, *receiver);
10395
10396 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010397 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010398}
10399
10400
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010401// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010402static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010403 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010404 Handle<SerializedScopeInfo> serialized_scope_info,
10405 ScopeInfo<>& scope_info,
10406 Handle<Context> context,
10407 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010408 // Fill all context locals to the context extension.
10409 for (int i = Context::MIN_CONTEXT_SLOTS;
10410 i < scope_info.number_of_context_slots();
10411 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010412 int context_index = serialized_scope_info->ContextSlotIndex(
10413 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010414
whesse@chromium.org7b260152011-06-20 15:33:18 +000010415 RETURN_IF_EMPTY_HANDLE_VALUE(
10416 isolate,
10417 SetProperty(scope_object,
10418 scope_info.context_slot_name(i),
10419 Handle<Object>(context->get(context_index), isolate),
10420 NONE,
10421 kNonStrictMode),
10422 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010423 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010424
10425 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010426}
10427
10428
10429// Create a plain JSObject which materializes the local scope for the specified
10430// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010431static Handle<JSObject> MaterializeLocalScope(
10432 Isolate* isolate,
10433 JavaScriptFrame* frame,
10434 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010435 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010436 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010437 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10438 ScopeInfo<> scope_info(*serialized_scope_info);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010439 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010440
10441 // Allocate and initialize a JSObject with all the arguments, stack locals
10442 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010443 Handle<JSObject> local_scope =
10444 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010445
10446 // First fill all parameters.
10447 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010448 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010449 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010450 SetProperty(local_scope,
10451 scope_info.parameter_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010452 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010453 NONE,
10454 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010455 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010456 }
10457
10458 // Second fill all stack locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010459 for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010460 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010461 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010462 SetProperty(local_scope,
10463 scope_info.stack_slot_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010464 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010465 NONE,
10466 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010467 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010468 }
10469
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010470 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10471 // Third fill all context locals.
10472 Handle<Context> frame_context(Context::cast(frame->context()));
10473 Handle<Context> function_context(frame_context->declaration_context());
10474 if (!CopyContextLocalsToScopeObject(isolate,
10475 serialized_scope_info, scope_info,
10476 function_context, local_scope)) {
10477 return Handle<JSObject>();
10478 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010479
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010480 // Finally copy any properties from the function context extension.
10481 // These will be variables introduced by eval.
10482 if (function_context->closure() == *function) {
10483 if (function_context->has_extension() &&
10484 !function_context->IsGlobalContext()) {
10485 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
10486 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
10487 for (int i = 0; i < keys->length(); i++) {
10488 // Names of variables introduced by eval are strings.
10489 ASSERT(keys->get(i)->IsString());
10490 Handle<String> key(String::cast(keys->get(i)));
10491 RETURN_IF_EMPTY_HANDLE_VALUE(
10492 isolate,
10493 SetProperty(local_scope,
10494 key,
10495 GetProperty(ext, key),
10496 NONE,
10497 kNonStrictMode),
10498 Handle<JSObject>());
10499 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010500 }
10501 }
10502 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010503
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010504 return local_scope;
10505}
10506
10507
10508// Create a plain JSObject which materializes the closure content for the
10509// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010510static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10511 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010512 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010513
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010514 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010515 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10516 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010517
10518 // Allocate and initialize a JSObject with all the content of theis function
10519 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010520 Handle<JSObject> closure_scope =
10521 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010522
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010523 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010524 if (!CopyContextLocalsToScopeObject(isolate,
10525 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010526 context, closure_scope)) {
10527 return Handle<JSObject>();
10528 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010529
10530 // Finally copy any properties from the function context extension. This will
10531 // be variables introduced by eval.
10532 if (context->has_extension()) {
10533 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010534 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010535 for (int i = 0; i < keys->length(); i++) {
10536 // Names of variables introduced by eval are strings.
10537 ASSERT(keys->get(i)->IsString());
10538 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010539 RETURN_IF_EMPTY_HANDLE_VALUE(
10540 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010541 SetProperty(closure_scope,
10542 key,
10543 GetProperty(ext, key),
10544 NONE,
10545 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010546 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010547 }
10548 }
10549
10550 return closure_scope;
10551}
10552
10553
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010554// Create a plain JSObject which materializes the scope for the specified
10555// catch context.
10556static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10557 Handle<Context> context) {
10558 ASSERT(context->IsCatchContext());
10559 Handle<String> name(String::cast(context->extension()));
10560 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10561 Handle<JSObject> catch_scope =
10562 isolate->factory()->NewJSObject(isolate->object_function());
10563 RETURN_IF_EMPTY_HANDLE_VALUE(
10564 isolate,
10565 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10566 Handle<JSObject>());
10567 return catch_scope;
10568}
10569
10570
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010571// Iterate over the actual scopes visible from a stack frame. All scopes are
10572// backed by an actual context except the local scope, which is inserted
10573// "artifically" in the context chain.
10574class ScopeIterator {
10575 public:
10576 enum ScopeType {
10577 ScopeTypeGlobal = 0,
10578 ScopeTypeLocal,
10579 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010580 ScopeTypeClosure,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010581 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010582 };
10583
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010584 ScopeIterator(Isolate* isolate,
10585 JavaScriptFrame* frame,
10586 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010587 : isolate_(isolate),
10588 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010589 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010590 function_(JSFunction::cast(frame->function())),
10591 context_(Context::cast(frame->context())),
10592 local_done_(false),
10593 at_local_(false) {
10594
10595 // Check whether the first scope is actually a local scope.
10596 if (context_->IsGlobalContext()) {
10597 // If there is a stack slot for .result then this local scope has been
10598 // created for evaluating top level code and it is not a real local scope.
10599 // Checking for the existence of .result seems fragile, but the scope info
10600 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010601 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010602 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010603 at_local_ = index < 0;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010604 } else if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010605 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010606 } else if (context_->closure() != *function_) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010607 // The context_ is a with or catch block from the outer function.
10608 ASSERT(context_->IsWithContext() || context_->IsCatchContext());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010609 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010610 }
10611 }
10612
10613 // More scopes?
10614 bool Done() { return context_.is_null(); }
10615
10616 // Move to the next scope.
10617 void Next() {
10618 // If at a local scope mark the local scope as passed.
10619 if (at_local_) {
10620 at_local_ = false;
10621 local_done_ = true;
10622
10623 // If the current context is not associated with the local scope the
10624 // current context is the next real scope, so don't move to the next
10625 // context in this case.
10626 if (context_->closure() != *function_) {
10627 return;
10628 }
10629 }
10630
10631 // The global scope is always the last in the chain.
10632 if (context_->IsGlobalContext()) {
10633 context_ = Handle<Context>();
10634 return;
10635 }
10636
10637 // Move to the next context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010638 context_ = Handle<Context>(context_->previous(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010639
10640 // If passing the local scope indicate that the current scope is now the
10641 // local scope.
10642 if (!local_done_ &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010643 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010644 at_local_ = true;
10645 }
10646 }
10647
10648 // Return the type of the current scope.
10649 int Type() {
10650 if (at_local_) {
10651 return ScopeTypeLocal;
10652 }
10653 if (context_->IsGlobalContext()) {
10654 ASSERT(context_->global()->IsGlobalObject());
10655 return ScopeTypeGlobal;
10656 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010657 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010658 return ScopeTypeClosure;
10659 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010660 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010661 return ScopeTypeCatch;
10662 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010663 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010664 return ScopeTypeWith;
10665 }
10666
10667 // Return the JavaScript object with the content of the current scope.
10668 Handle<JSObject> ScopeObject() {
10669 switch (Type()) {
10670 case ScopeIterator::ScopeTypeGlobal:
10671 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010672 case ScopeIterator::ScopeTypeLocal:
10673 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010674 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010675 case ScopeIterator::ScopeTypeWith:
10676 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010677 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
10678 case ScopeIterator::ScopeTypeCatch:
10679 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010680 case ScopeIterator::ScopeTypeClosure:
10681 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010682 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010683 }
10684 UNREACHABLE();
10685 return Handle<JSObject>();
10686 }
10687
10688 // Return the context for this scope. For the local context there might not
10689 // be an actual context.
10690 Handle<Context> CurrentContext() {
10691 if (at_local_ && context_->closure() != *function_) {
10692 return Handle<Context>();
10693 }
10694 return context_;
10695 }
10696
10697#ifdef DEBUG
10698 // Debug print of the content of the current scope.
10699 void DebugPrint() {
10700 switch (Type()) {
10701 case ScopeIterator::ScopeTypeGlobal:
10702 PrintF("Global:\n");
10703 CurrentContext()->Print();
10704 break;
10705
10706 case ScopeIterator::ScopeTypeLocal: {
10707 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010708 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010709 scope_info.Print();
10710 if (!CurrentContext().is_null()) {
10711 CurrentContext()->Print();
10712 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010713 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010714 if (extension->IsJSContextExtensionObject()) {
10715 extension->Print();
10716 }
10717 }
10718 }
10719 break;
10720 }
10721
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010722 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010723 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010724 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010725 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010726
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010727 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010728 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010729 CurrentContext()->extension()->Print();
10730 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010731 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010732
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010733 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010734 PrintF("Closure:\n");
10735 CurrentContext()->Print();
10736 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010737 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010738 if (extension->IsJSContextExtensionObject()) {
10739 extension->Print();
10740 }
10741 }
10742 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010743
10744 default:
10745 UNREACHABLE();
10746 }
10747 PrintF("\n");
10748 }
10749#endif
10750
10751 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010752 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010753 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010754 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010755 Handle<JSFunction> function_;
10756 Handle<Context> context_;
10757 bool local_done_;
10758 bool at_local_;
10759
10760 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10761};
10762
10763
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010764RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010765 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010766 ASSERT(args.length() == 2);
10767
10768 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010769 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010770 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10771 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010772 if (!maybe_check->ToObject(&check)) return maybe_check;
10773 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010774 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10775
10776 // Get the frame where the debugging is performed.
10777 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010778 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010779 JavaScriptFrame* frame = it.frame();
10780
10781 // Count the visible scopes.
10782 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010783 for (ScopeIterator it(isolate, frame, 0);
10784 !it.Done();
10785 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010786 n++;
10787 }
10788
10789 return Smi::FromInt(n);
10790}
10791
10792
10793static const int kScopeDetailsTypeIndex = 0;
10794static const int kScopeDetailsObjectIndex = 1;
10795static const int kScopeDetailsSize = 2;
10796
10797// Return an array with scope details
10798// args[0]: number: break id
10799// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010800// args[2]: number: inlined frame index
10801// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010802//
10803// The array returned contains the following information:
10804// 0: Scope type
10805// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010806RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010807 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010808 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010809
10810 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010811 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010812 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10813 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010814 if (!maybe_check->ToObject(&check)) return maybe_check;
10815 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010816 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010817 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
10818 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010819
10820 // Get the frame where the debugging is performed.
10821 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010822 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010823 JavaScriptFrame* frame = frame_it.frame();
10824
10825 // Find the requested scope.
10826 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010827 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010828 for (; !it.Done() && n < index; it.Next()) {
10829 n++;
10830 }
10831 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010832 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010833 }
10834
10835 // Calculate the size of the result.
10836 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010837 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010838
10839 // Fill in scope details.
10840 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010841 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010842 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010843 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010844
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010845 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010846}
10847
10848
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010849RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010850 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010851 ASSERT(args.length() == 0);
10852
10853#ifdef DEBUG
10854 // Print the scopes for the top frame.
10855 StackFrameLocator locator;
10856 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010857 for (ScopeIterator it(isolate, frame, 0);
10858 !it.Done();
10859 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010860 it.DebugPrint();
10861 }
10862#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010863 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010864}
10865
10866
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010867RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010868 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010869 ASSERT(args.length() == 1);
10870
10871 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010872 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010873 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10874 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010875 if (!maybe_result->ToObject(&result)) return maybe_result;
10876 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010877
10878 // Count all archived V8 threads.
10879 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010880 for (ThreadState* thread =
10881 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010882 thread != NULL;
10883 thread = thread->Next()) {
10884 n++;
10885 }
10886
10887 // Total number of threads is current thread and archived threads.
10888 return Smi::FromInt(n + 1);
10889}
10890
10891
10892static const int kThreadDetailsCurrentThreadIndex = 0;
10893static const int kThreadDetailsThreadIdIndex = 1;
10894static const int kThreadDetailsSize = 2;
10895
10896// Return an array with thread details
10897// args[0]: number: break id
10898// args[1]: number: thread index
10899//
10900// The array returned contains the following information:
10901// 0: Is current thread?
10902// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010903RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010904 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010905 ASSERT(args.length() == 2);
10906
10907 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010908 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010909 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10910 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010911 if (!maybe_check->ToObject(&check)) return maybe_check;
10912 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010913 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10914
10915 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010916 Handle<FixedArray> details =
10917 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010918
10919 // Thread index 0 is current thread.
10920 if (index == 0) {
10921 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010922 details->set(kThreadDetailsCurrentThreadIndex,
10923 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010924 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010925 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010926 } else {
10927 // Find the thread with the requested index.
10928 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010929 ThreadState* thread =
10930 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010931 while (index != n && thread != NULL) {
10932 thread = thread->Next();
10933 n++;
10934 }
10935 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010936 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010937 }
10938
10939 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010940 details->set(kThreadDetailsCurrentThreadIndex,
10941 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010942 details->set(kThreadDetailsThreadIdIndex,
10943 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010944 }
10945
10946 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010947 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010948}
10949
10950
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010951// Sets the disable break state
10952// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010953RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010954 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010955 ASSERT(args.length() == 1);
10956 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010957 isolate->debug()->set_disable_break(disable_break);
10958 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010959}
10960
10961
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010962RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010963 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010964 ASSERT(args.length() == 1);
10965
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010966 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10967 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010968 // Find the number of break points
10969 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010970 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010971 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010972 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010973 Handle<FixedArray>::cast(break_locations));
10974}
10975
10976
10977// Set a break point in a function
10978// args[0]: function
10979// args[1]: number: break source position (within the function source)
10980// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010981RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010982 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010983 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010984 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10985 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010986 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10987 RUNTIME_ASSERT(source_position >= 0);
10988 Handle<Object> break_point_object_arg = args.at<Object>(2);
10989
10990 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010991 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10992 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010993
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010994 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010995}
10996
10997
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010998Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10999 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011000 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011001 // Iterate the heap looking for SharedFunctionInfo generated from the
11002 // script. The inner most SharedFunctionInfo containing the source position
11003 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011004 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011005 // which is found is not compiled it is compiled and the heap is iterated
11006 // again as the compilation might create inner functions from the newly
11007 // compiled function and the actual requested break point might be in one of
11008 // these functions.
11009 bool done = false;
11010 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011011 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011012 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011013 while (!done) {
11014 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011015 for (HeapObject* obj = iterator.next();
11016 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011017 if (obj->IsSharedFunctionInfo()) {
11018 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11019 if (shared->script() == *script) {
11020 // If the SharedFunctionInfo found has the requested script data and
11021 // contains the source position it is a candidate.
11022 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000011023 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011024 start_position = shared->start_position();
11025 }
11026 if (start_position <= position &&
11027 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000011028 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011029 // candidate this is the new candidate.
11030 if (target.is_null()) {
11031 target_start_position = start_position;
11032 target = shared;
11033 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011034 if (target_start_position == start_position &&
11035 shared->end_position() == target->end_position()) {
11036 // If a top-level function contain only one function
11037 // declartion the source for the top-level and the function is
11038 // the same. In that case prefer the non top-level function.
11039 if (!shared->is_toplevel()) {
11040 target_start_position = start_position;
11041 target = shared;
11042 }
11043 } else if (target_start_position <= start_position &&
11044 shared->end_position() <= target->end_position()) {
11045 // This containment check includes equality as a function inside
11046 // a top-level function can share either start or end position
11047 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011048 target_start_position = start_position;
11049 target = shared;
11050 }
11051 }
11052 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011053 }
11054 }
11055 }
11056
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011057 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011058 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011059 }
11060
11061 // If the candidate found is compiled we are done. NOTE: when lazy
11062 // compilation of inner functions is introduced some additional checking
11063 // needs to be done here to compile inner functions.
11064 done = target->is_compiled();
11065 if (!done) {
11066 // If the candidate is not compiled compile it to reveal any inner
11067 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011068 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011069 }
11070 }
11071
11072 return *target;
11073}
11074
11075
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011076// Changes the state of a break point in a script and returns source position
11077// where break point was set. NOTE: Regarding performance see the NOTE for
11078// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011079// args[0]: script to set break point in
11080// args[1]: number: break source position (within the script source)
11081// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011082RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011083 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011084 ASSERT(args.length() == 3);
11085 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11086 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11087 RUNTIME_ASSERT(source_position >= 0);
11088 Handle<Object> break_point_object_arg = args.at<Object>(2);
11089
11090 // Get the script from the script wrapper.
11091 RUNTIME_ASSERT(wrapper->value()->IsScript());
11092 Handle<Script> script(Script::cast(wrapper->value()));
11093
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011094 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011095 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011096 if (!result->IsUndefined()) {
11097 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11098 // Find position within function. The script position might be before the
11099 // source position of the first function.
11100 int position;
11101 if (shared->start_position() > source_position) {
11102 position = 0;
11103 } else {
11104 position = source_position - shared->start_position();
11105 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011106 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011107 position += shared->start_position();
11108 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011109 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011110 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011111}
11112
11113
11114// Clear a break point
11115// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011116RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011117 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011118 ASSERT(args.length() == 1);
11119 Handle<Object> break_point_object_arg = args.at<Object>(0);
11120
11121 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011122 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011123
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011124 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011125}
11126
11127
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011128// Change the state of break on exceptions.
11129// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11130// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011131RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011132 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011133 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011134 RUNTIME_ASSERT(args[0]->IsNumber());
11135 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011136
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011137 // If the number doesn't match an enum value, the ChangeBreakOnException
11138 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011139 ExceptionBreakType type =
11140 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011141 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011142 isolate->debug()->ChangeBreakOnException(type, enable);
11143 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011144}
11145
11146
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011147// Returns the state of break on exceptions
11148// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011149RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011150 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011151 ASSERT(args.length() == 1);
11152 RUNTIME_ASSERT(args[0]->IsNumber());
11153
11154 ExceptionBreakType type =
11155 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011156 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011157 return Smi::FromInt(result);
11158}
11159
11160
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011161// Prepare for stepping
11162// args[0]: break id for checking execution state
11163// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011164// args[2]: number of times to perform the step, for step out it is the number
11165// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011166RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011167 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011168 ASSERT(args.length() == 3);
11169 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011170 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011171 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11172 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011173 if (!maybe_check->ToObject(&check)) return maybe_check;
11174 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011175 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011176 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011177 }
11178
11179 // Get the step action and check validity.
11180 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11181 if (step_action != StepIn &&
11182 step_action != StepNext &&
11183 step_action != StepOut &&
11184 step_action != StepInMin &&
11185 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011186 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011187 }
11188
11189 // Get the number of steps.
11190 int step_count = NumberToInt32(args[2]);
11191 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011192 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011193 }
11194
ager@chromium.orga1645e22009-09-09 19:27:10 +000011195 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011196 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011197
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011198 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011199 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11200 step_count);
11201 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011202}
11203
11204
11205// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011206RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011207 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011208 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011209 isolate->debug()->ClearStepping();
11210 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011211}
11212
11213
11214// Creates a copy of the with context chain. The copy of the context chain is
11215// is linked to the function context supplied.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011216static Handle<Context> CopyWithContextChain(Isolate* isolate,
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011217 Handle<JSFunction> function,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011218 Handle<Context> current,
11219 Handle<Context> base) {
11220 // At the end of the chain. Return the base context to link to.
11221 if (current->IsFunctionContext() || current->IsGlobalContext()) {
11222 return base;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011223 }
11224
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011225 // Recursively copy the with and catch contexts.
11226 HandleScope scope(isolate);
11227 Handle<Context> previous(current->previous());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011228 Handle<Context> new_previous =
11229 CopyWithContextChain(isolate, function, previous, base);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011230 Handle<Context> new_current;
11231 if (current->IsCatchContext()) {
11232 Handle<String> name(String::cast(current->extension()));
11233 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11234 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011235 isolate->factory()->NewCatchContext(function,
11236 new_previous,
11237 name,
11238 thrown_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011239 } else {
11240 Handle<JSObject> extension(JSObject::cast(current->extension()));
11241 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011242 isolate->factory()->NewWithContext(function, new_previous, extension);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011243 }
11244 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011245}
11246
11247
11248// Helper function to find or create the arguments object for
11249// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011250static Handle<Object> GetArgumentsObject(Isolate* isolate,
11251 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011252 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011253 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011254 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011255 const ScopeInfo<>* sinfo,
11256 Handle<Context> function_context) {
11257 // Try to find the value of 'arguments' to pass as parameter. If it is not
11258 // found (that is the debugged function does not reference 'arguments' and
11259 // does not support eval) then create an 'arguments' object.
11260 int index;
11261 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011262 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011263 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011264 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011265 }
11266 }
11267
11268 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011269 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
11270 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011271 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011272 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011273 }
11274 }
11275
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011276 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
11277
11278 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011279 Handle<JSObject> arguments =
11280 isolate->factory()->NewArgumentsObject(function, length);
11281 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011282
11283 AssertNoAllocation no_gc;
11284 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011285 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011286 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011287 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011288 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011289 return arguments;
11290}
11291
11292
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011293static const char kSourceStr[] =
11294 "(function(arguments,__source__){return eval(__source__);})";
11295
11296
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011297// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011298// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011299// extension part has all the parameters and locals of the function on the
11300// stack frame. A function which calls eval with the code to evaluate is then
11301// compiled in this context and called in this context. As this context
11302// replaces the context of the function on the stack frame a new (empty)
11303// function is created as well to be used as the closure for the context.
11304// This function and the context acts as replacements for the function on the
11305// stack frame presenting the same view of the values of parameters and
11306// local variables as if the piece of JavaScript was evaluated at the point
11307// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011308RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011309 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011310
11311 // Check the execution state and decode arguments frame and source to be
11312 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011313 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011314 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011315 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11316 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011317 if (!maybe_check_result->ToObject(&check_result)) {
11318 return maybe_check_result;
11319 }
11320 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011321 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011322 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11323 CONVERT_ARG_CHECKED(String, source, 3);
11324 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
11325 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011326
11327 // Handle the processing of break.
11328 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011329
11330 // Get the frame where the debugging is performed.
11331 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011332 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011333 JavaScriptFrame* frame = it.frame();
11334 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000011335 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011336 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011337
11338 // Traverse the saved contexts chain to find the active context for the
11339 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011340 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011341 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011342 save = save->prev();
11343 }
11344 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011345 SaveContext savex(isolate);
11346 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011347
11348 // Create the (empty) function replacing the function on the stack frame for
11349 // the purpose of evaluating in the context created below. It is important
11350 // that this function does not describe any parameters and local variables
11351 // in the context. If it does then this will cause problems with the lookup
11352 // in Context::Lookup, where context slots for parameters and local variables
11353 // are looked at before the extension object.
11354 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011355 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11356 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011357 go_between->set_context(function->context());
11358#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011359 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011360 ASSERT(go_between_sinfo.number_of_parameters() == 0);
11361 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
11362#endif
11363
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011364 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011365 Handle<JSObject> local_scope = MaterializeLocalScope(
11366 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011367 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011368
11369 // Allocate a new context for the debug evaluation and set the extension
11370 // object build.
11371 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011372 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11373 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011374 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011375 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011376 Handle<Context> frame_context(Context::cast(frame->context()));
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011377 Handle<Context> function_context(frame_context->declaration_context());
11378 context = CopyWithContextChain(isolate, go_between, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011379
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011380 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011381 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011382 context =
11383 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011384 }
11385
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011386 // Wrap the evaluation statement in a new function compiled in the newly
11387 // created context. The function has one parameter which has to be called
11388 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011389 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011390 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011391
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011392 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011393 isolate->factory()->NewStringFromAscii(
11394 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011395
11396 // Currently, the eval code will be executed in non-strict mode,
11397 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011398 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011399 Compiler::CompileEval(function_source,
11400 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011401 context->IsGlobalContext(),
11402 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011403 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011404 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011405 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011406
11407 // Invoke the result of the compilation to get the evaluation function.
11408 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011409 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011410 Handle<Object> evaluation_function =
11411 Execution::Call(compiled_function, receiver, 0, NULL,
11412 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011413 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011414
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011415 Handle<Object> arguments = GetArgumentsObject(isolate,
11416 frame, inlined_frame_index,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011417 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011418 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011419
11420 // Invoke the evaluation function and return the result.
11421 const int argc = 2;
11422 Object** argv[argc] = { arguments.location(),
11423 Handle<Object>::cast(source).location() };
11424 Handle<Object> result =
11425 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11426 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011427 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011428
11429 // Skip the global proxy as it has no properties and always delegates to the
11430 // real global object.
11431 if (result->IsJSGlobalProxy()) {
11432 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11433 }
11434
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011435 return *result;
11436}
11437
11438
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011439RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011440 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011441
11442 // Check the execution state and decode arguments frame and source to be
11443 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011444 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011445 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011446 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11447 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011448 if (!maybe_check_result->ToObject(&check_result)) {
11449 return maybe_check_result;
11450 }
11451 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011452 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011453 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011454 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011455
11456 // Handle the processing of break.
11457 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011458
11459 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011460 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011461 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011462 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011463 top = top->prev();
11464 }
11465 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011466 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011467 }
11468
11469 // Get the global context now set to the top context from before the
11470 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011471 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011472
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011473 bool is_global = true;
11474
11475 if (additional_context->IsJSObject()) {
11476 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011477 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11478 isolate->factory()->empty_string(),
11479 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011480 go_between->set_context(*context);
11481 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011482 isolate->factory()->NewFunctionContext(
11483 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011484 context->set_extension(JSObject::cast(*additional_context));
11485 is_global = false;
11486 }
11487
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011488 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011489 // Currently, the eval code will be executed in non-strict mode,
11490 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011491 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011492 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011493 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011494 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011495 Handle<JSFunction>(
11496 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11497 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011498
11499 // Invoke the result of the compilation to get the evaluation function.
11500 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011501 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011502 Handle<Object> result =
11503 Execution::Call(compiled_function, receiver, 0, NULL,
11504 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011505 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011506 return *result;
11507}
11508
11509
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011510RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011511 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011512 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011513
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011514 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011515 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011516
11517 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011518 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011519 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11520 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11521 // because using
11522 // instances->set(i, *GetScriptWrapper(script))
11523 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11524 // already have deferenced the instances handle.
11525 Handle<JSValue> wrapper = GetScriptWrapper(script);
11526 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011527 }
11528
11529 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011530 Handle<JSObject> result =
11531 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011532 Handle<JSArray>::cast(result)->SetContent(*instances);
11533 return *result;
11534}
11535
11536
11537// Helper function used by Runtime_DebugReferencedBy below.
11538static int DebugReferencedBy(JSObject* target,
11539 Object* instance_filter, int max_references,
11540 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011541 JSFunction* arguments_function) {
11542 NoHandleAllocation ha;
11543 AssertNoAllocation no_alloc;
11544
11545 // Iterate the heap.
11546 int count = 0;
11547 JSObject* last = NULL;
11548 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011549 HeapObject* heap_obj = NULL;
11550 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011551 (max_references == 0 || count < max_references)) {
11552 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011553 if (heap_obj->IsJSObject()) {
11554 // Skip context extension objects and argument arrays as these are
11555 // checked in the context of functions using them.
11556 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011557 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011558 obj->map()->constructor() == arguments_function) {
11559 continue;
11560 }
11561
11562 // Check if the JS object has a reference to the object looked for.
11563 if (obj->ReferencesObject(target)) {
11564 // Check instance filter if supplied. This is normally used to avoid
11565 // references from mirror objects (see Runtime_IsInPrototypeChain).
11566 if (!instance_filter->IsUndefined()) {
11567 Object* V = obj;
11568 while (true) {
11569 Object* prototype = V->GetPrototype();
11570 if (prototype->IsNull()) {
11571 break;
11572 }
11573 if (instance_filter == prototype) {
11574 obj = NULL; // Don't add this object.
11575 break;
11576 }
11577 V = prototype;
11578 }
11579 }
11580
11581 if (obj != NULL) {
11582 // Valid reference found add to instance array if supplied an update
11583 // count.
11584 if (instances != NULL && count < instances_size) {
11585 instances->set(count, obj);
11586 }
11587 last = obj;
11588 count++;
11589 }
11590 }
11591 }
11592 }
11593
11594 // Check for circular reference only. This can happen when the object is only
11595 // referenced from mirrors and has a circular reference in which case the
11596 // object is not really alive and would have been garbage collected if not
11597 // referenced from the mirror.
11598 if (count == 1 && last == target) {
11599 count = 0;
11600 }
11601
11602 // Return the number of referencing objects found.
11603 return count;
11604}
11605
11606
11607// Scan the heap for objects with direct references to an object
11608// args[0]: the object to find references to
11609// args[1]: constructor function for instances to exclude (Mirror)
11610// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011611RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011612 ASSERT(args.length() == 3);
11613
11614 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011615 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011616
11617 // Check parameters.
11618 CONVERT_CHECKED(JSObject, target, args[0]);
11619 Object* instance_filter = args[1];
11620 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11621 instance_filter->IsJSObject());
11622 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11623 RUNTIME_ASSERT(max_references >= 0);
11624
11625 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011626 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011627 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011628 JSFunction* arguments_function =
11629 JSFunction::cast(arguments_boilerplate->map()->constructor());
11630
11631 // Get the number of referencing objects.
11632 int count;
11633 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011634 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011635
11636 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011637 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011638 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011639 if (!maybe_object->ToObject(&object)) return maybe_object;
11640 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011641 FixedArray* instances = FixedArray::cast(object);
11642
11643 // Fill the referencing objects.
11644 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011645 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011646
11647 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011648 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011649 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11650 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011651 if (!maybe_result->ToObject(&result)) return maybe_result;
11652 }
11653 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011654 return result;
11655}
11656
11657
11658// Helper function used by Runtime_DebugConstructedBy below.
11659static int DebugConstructedBy(JSFunction* constructor, int max_references,
11660 FixedArray* instances, int instances_size) {
11661 AssertNoAllocation no_alloc;
11662
11663 // Iterate the heap.
11664 int count = 0;
11665 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011666 HeapObject* heap_obj = NULL;
11667 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011668 (max_references == 0 || count < max_references)) {
11669 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011670 if (heap_obj->IsJSObject()) {
11671 JSObject* obj = JSObject::cast(heap_obj);
11672 if (obj->map()->constructor() == constructor) {
11673 // Valid reference found add to instance array if supplied an update
11674 // count.
11675 if (instances != NULL && count < instances_size) {
11676 instances->set(count, obj);
11677 }
11678 count++;
11679 }
11680 }
11681 }
11682
11683 // Return the number of referencing objects found.
11684 return count;
11685}
11686
11687
11688// Scan the heap for objects constructed by a specific function.
11689// args[0]: the constructor to find instances of
11690// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011691RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011692 ASSERT(args.length() == 2);
11693
11694 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011695 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011696
11697 // Check parameters.
11698 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11699 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11700 RUNTIME_ASSERT(max_references >= 0);
11701
11702 // Get the number of referencing objects.
11703 int count;
11704 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11705
11706 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011707 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011708 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011709 if (!maybe_object->ToObject(&object)) return maybe_object;
11710 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011711 FixedArray* instances = FixedArray::cast(object);
11712
11713 // Fill the referencing objects.
11714 count = DebugConstructedBy(constructor, max_references, instances, count);
11715
11716 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011717 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011718 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11719 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011720 if (!maybe_result->ToObject(&result)) return maybe_result;
11721 }
11722 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011723 return result;
11724}
11725
11726
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011727// Find the effective prototype object as returned by __proto__.
11728// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011729RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011730 ASSERT(args.length() == 1);
11731
11732 CONVERT_CHECKED(JSObject, obj, args[0]);
11733
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011734 // Use the __proto__ accessor.
11735 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011736}
11737
11738
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011739RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011740 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011741 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011742 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011743}
11744
11745
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011746RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011747#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011748 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011749 ASSERT(args.length() == 1);
11750 // Get the function and make sure it is compiled.
11751 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011752 Handle<SharedFunctionInfo> shared(func->shared());
11753 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011754 return Failure::Exception();
11755 }
11756 func->code()->PrintLn();
11757#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011758 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011759}
ager@chromium.org9085a012009-05-11 19:22:57 +000011760
11761
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011762RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011763#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011764 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011765 ASSERT(args.length() == 1);
11766 // Get the function and make sure it is compiled.
11767 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011768 Handle<SharedFunctionInfo> shared(func->shared());
11769 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011770 return Failure::Exception();
11771 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011772 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011773#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011774 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011775}
11776
11777
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011778RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011779 NoHandleAllocation ha;
11780 ASSERT(args.length() == 1);
11781
11782 CONVERT_CHECKED(JSFunction, f, args[0]);
11783 return f->shared()->inferred_name();
11784}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011785
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011786
11787static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011788 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011789 AssertNoAllocation no_allocations;
11790
11791 int counter = 0;
11792 int buffer_size = buffer->length();
11793 HeapIterator iterator;
11794 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11795 ASSERT(obj != NULL);
11796 if (!obj->IsSharedFunctionInfo()) {
11797 continue;
11798 }
11799 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11800 if (shared->script() != script) {
11801 continue;
11802 }
11803 if (counter < buffer_size) {
11804 buffer->set(counter, shared);
11805 }
11806 counter++;
11807 }
11808 return counter;
11809}
11810
11811// For a script finds all SharedFunctionInfo's in the heap that points
11812// to this script. Returns JSArray of SharedFunctionInfo wrapped
11813// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011814RUNTIME_FUNCTION(MaybeObject*,
11815 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011816 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011817 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011818 CONVERT_CHECKED(JSValue, script_value, args[0]);
11819
11820 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11821
11822 const int kBufferSize = 32;
11823
11824 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011825 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011826 int number = FindSharedFunctionInfosForScript(*script, *array);
11827 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011828 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011829 FindSharedFunctionInfosForScript(*script, *array);
11830 }
11831
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011832 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011833 result->set_length(Smi::FromInt(number));
11834
11835 LiveEdit::WrapSharedFunctionInfos(result);
11836
11837 return *result;
11838}
11839
11840// For a script calculates compilation information about all its functions.
11841// The script source is explicitly specified by the second argument.
11842// The source of the actual script is not used, however it is important that
11843// all generated code keeps references to this particular instance of script.
11844// Returns a JSArray of compilation infos. The array is ordered so that
11845// each function with all its descendant is always stored in a continues range
11846// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011847RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011848 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011849 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011850 CONVERT_CHECKED(JSValue, script, args[0]);
11851 CONVERT_ARG_CHECKED(String, source, 1);
11852 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11853
11854 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11855
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011856 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011857 return Failure::Exception();
11858 }
11859
11860 return result;
11861}
11862
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011863// Changes the source of the script to a new_source.
11864// If old_script_name is provided (i.e. is a String), also creates a copy of
11865// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011866RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011867 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011868 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011869 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11870 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011871 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011872
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011873 CONVERT_CHECKED(Script, original_script_pointer,
11874 original_script_value->value());
11875 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011876
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011877 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11878 new_source,
11879 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011880
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011881 if (old_script->IsScript()) {
11882 Handle<Script> script_handle(Script::cast(old_script));
11883 return *(GetScriptWrapper(script_handle));
11884 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011885 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011886 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011887}
11888
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011889
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011890RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011891 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011892 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011893 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11894 return LiveEdit::FunctionSourceUpdated(shared_info);
11895}
11896
11897
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011898// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011899RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011900 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011901 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011902 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11903 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11904
ager@chromium.orgac091b72010-05-05 07:34:42 +000011905 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011906}
11907
11908// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011909RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011910 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011911 HandleScope scope(isolate);
11912 Handle<Object> function_object(args[0], isolate);
11913 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011914
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011915 if (function_object->IsJSValue()) {
11916 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11917 if (script_object->IsJSValue()) {
11918 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011919 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011920 }
11921
11922 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11923 } else {
11924 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11925 // and we check it in this function.
11926 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011927
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011928 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011929}
11930
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011931
11932// In a code of a parent function replaces original function as embedded object
11933// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011934RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011935 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011936 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011937
11938 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11939 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11940 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11941
11942 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11943 subst_wrapper);
11944
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011945 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011946}
11947
11948
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011949// Updates positions of a shared function info (first parameter) according
11950// to script source change. Text change is described in second parameter as
11951// array of groups of 3 numbers:
11952// (change_begin, change_end, change_end_new_position).
11953// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011954RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011955 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011956 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011957 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11958 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11959
ager@chromium.orgac091b72010-05-05 07:34:42 +000011960 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011961}
11962
11963
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011964// For array of SharedFunctionInfo's (each wrapped in JSValue)
11965// checks that none of them have activations on stacks (of any thread).
11966// Returns array of the same length with corresponding results of
11967// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011968RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011969 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011970 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011971 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011972 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011973
ager@chromium.org357bf652010-04-12 11:30:10 +000011974 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011975}
11976
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011977// Compares 2 strings line-by-line, then token-wise and returns diff in form
11978// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11979// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011980RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011981 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011982 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011983 CONVERT_ARG_CHECKED(String, s1, 0);
11984 CONVERT_ARG_CHECKED(String, s2, 1);
11985
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011986 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011987}
11988
11989
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011990// A testing entry. Returns statement position which is the closest to
11991// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011992RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011993 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011994 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011995 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11996 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11997
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011998 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011999
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012000 if (code->kind() != Code::FUNCTION &&
12001 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012002 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012003 }
12004
12005 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012006 int closest_pc = 0;
12007 int distance = kMaxInt;
12008 while (!it.done()) {
12009 int statement_position = static_cast<int>(it.rinfo()->data());
12010 // Check if this break point is closer that what was previously found.
12011 if (source_position <= statement_position &&
12012 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012013 closest_pc =
12014 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012015 distance = statement_position - source_position;
12016 // Check whether we can't get any closer.
12017 if (distance == 0) break;
12018 }
12019 it.next();
12020 }
12021
12022 return Smi::FromInt(closest_pc);
12023}
12024
12025
ager@chromium.org357bf652010-04-12 11:30:10 +000012026// Calls specified function with or without entering the debugger.
12027// This is used in unit tests to run code as if debugger is entered or simply
12028// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012029RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012030 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012031 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012032 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12033 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12034
12035 Handle<Object> result;
12036 bool pending_exception;
12037 {
12038 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012039 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012040 &pending_exception);
12041 } else {
12042 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012043 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012044 &pending_exception);
12045 }
12046 }
12047 if (!pending_exception) {
12048 return *result;
12049 } else {
12050 return Failure::Exception();
12051 }
12052}
12053
12054
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012055// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012056RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012057 CONVERT_CHECKED(String, arg, args[0]);
12058 SmartPointer<char> flags =
12059 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12060 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012061 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012062}
12063
12064
12065// Performs a GC.
12066// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012067RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012068 isolate->heap()->CollectAllGarbage(true);
12069 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012070}
12071
12072
12073// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012074RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012075 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012076 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012077 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012078 }
12079 return Smi::FromInt(usage);
12080}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012081
12082
12083// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012084RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012085#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012086 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012087#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012088 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012089#endif
12090}
12091
12092
12093// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012094RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012095#ifdef LIVE_OBJECT_LIST
12096 return LiveObjectList::Capture();
12097#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012098 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012099#endif
12100}
12101
12102
12103// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012104RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012105#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012106 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012107 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012108 return success ? isolate->heap()->true_value() :
12109 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012110#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012111 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012112#endif
12113}
12114
12115
12116// Generates the response to a debugger request for a dump of the objects
12117// contained in the difference between the captured live object lists
12118// specified by id1 and id2.
12119// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12120// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012121RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012122#ifdef LIVE_OBJECT_LIST
12123 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012124 CONVERT_SMI_ARG_CHECKED(id1, 0);
12125 CONVERT_SMI_ARG_CHECKED(id2, 1);
12126 CONVERT_SMI_ARG_CHECKED(start, 2);
12127 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012128 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12129 EnterDebugger enter_debugger;
12130 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12131#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012132 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012133#endif
12134}
12135
12136
12137// Gets the specified object as requested by the debugger.
12138// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012139RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012140#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012141 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012142 Object* result = LiveObjectList::GetObj(obj_id);
12143 return result;
12144#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012145 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012146#endif
12147}
12148
12149
12150// Gets the obj id for the specified address if valid.
12151// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012152RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012153#ifdef LIVE_OBJECT_LIST
12154 HandleScope scope;
12155 CONVERT_ARG_CHECKED(String, address, 0);
12156 Object* result = LiveObjectList::GetObjId(address);
12157 return result;
12158#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012159 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012160#endif
12161}
12162
12163
12164// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012165RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012166#ifdef LIVE_OBJECT_LIST
12167 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012168 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012169 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12170 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12171 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12172 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12173 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12174
12175 Handle<JSObject> instance_filter;
12176 if (args[1]->IsJSObject()) {
12177 instance_filter = args.at<JSObject>(1);
12178 }
12179 bool verbose = false;
12180 if (args[2]->IsBoolean()) {
12181 verbose = args[2]->IsTrue();
12182 }
12183 int start = 0;
12184 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012185 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012186 }
12187 int limit = Smi::kMaxValue;
12188 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012189 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012190 }
12191
12192 return LiveObjectList::GetObjRetainers(obj_id,
12193 instance_filter,
12194 verbose,
12195 start,
12196 limit,
12197 filter_obj);
12198#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012199 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012200#endif
12201}
12202
12203
12204// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012205RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012206#ifdef LIVE_OBJECT_LIST
12207 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012208 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12209 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012210 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12211
12212 Handle<JSObject> instance_filter;
12213 if (args[2]->IsJSObject()) {
12214 instance_filter = args.at<JSObject>(2);
12215 }
12216
12217 Object* result =
12218 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12219 return result;
12220#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012221 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012222#endif
12223}
12224
12225
12226// Generates the response to a debugger request for a list of all
12227// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012228RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012229#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012230 CONVERT_SMI_ARG_CHECKED(start, 0);
12231 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012232 return LiveObjectList::Info(start, count);
12233#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012234 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012235#endif
12236}
12237
12238
12239// Gets a dump of the specified object as requested by the debugger.
12240// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012241RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012242#ifdef LIVE_OBJECT_LIST
12243 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012244 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012245 Object* result = LiveObjectList::PrintObj(obj_id);
12246 return result;
12247#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012248 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012249#endif
12250}
12251
12252
12253// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012254RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012255#ifdef LIVE_OBJECT_LIST
12256 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012257 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012258#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012259 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012260#endif
12261}
12262
12263
12264// Generates the response to a debugger request for a summary of the types
12265// of objects in the difference between the captured live object lists
12266// specified by id1 and id2.
12267// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12268// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012269RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012270#ifdef LIVE_OBJECT_LIST
12271 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012272 CONVERT_SMI_ARG_CHECKED(id1, 0);
12273 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012274 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
12275
12276 EnterDebugger enter_debugger;
12277 return LiveObjectList::Summarize(id1, id2, filter_obj);
12278#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012279 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012280#endif
12281}
12282
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012283#endif // ENABLE_DEBUGGER_SUPPORT
12284
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012285
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012286RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012287 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012288 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012289 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012290}
12291
12292
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012293RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012294 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012295 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012296 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012297}
12298
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012299
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012300// Finds the script object from the script data. NOTE: This operation uses
12301// heap traversal to find the function generated for the source position
12302// for the requested break point. For lazily compiled functions several heap
12303// traversals might be required rendering this operation as a rather slow
12304// operation. However for setting break points which is normally done through
12305// some kind of user interaction the performance is not crucial.
12306static Handle<Object> Runtime_GetScriptFromScriptName(
12307 Handle<String> script_name) {
12308 // Scan the heap for Script objects to find the script with the requested
12309 // script data.
12310 Handle<Script> script;
12311 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012312 HeapObject* obj = NULL;
12313 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012314 // If a script is found check if it has the script data requested.
12315 if (obj->IsScript()) {
12316 if (Script::cast(obj)->name()->IsString()) {
12317 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12318 script = Handle<Script>(Script::cast(obj));
12319 }
12320 }
12321 }
12322 }
12323
12324 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012325 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012326
12327 // Return the script found.
12328 return GetScriptWrapper(script);
12329}
12330
12331
12332// Get the script object from script data. NOTE: Regarding performance
12333// see the NOTE for GetScriptFromScriptData.
12334// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012335RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012336 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012337
12338 ASSERT(args.length() == 1);
12339
12340 CONVERT_CHECKED(String, script_name, args[0]);
12341
12342 // Find the requested script.
12343 Handle<Object> result =
12344 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12345 return *result;
12346}
12347
12348
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012349// Determines whether the given stack frame should be displayed in
12350// a stack trace. The caller is the error constructor that asked
12351// for the stack trace to be collected. The first time a construct
12352// call to this function is encountered it is skipped. The seen_caller
12353// in/out parameter is used to remember if the caller has been seen
12354// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012355static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12356 Object* caller,
12357 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012358 // Only display JS frames.
12359 if (!raw_frame->is_java_script())
12360 return false;
12361 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12362 Object* raw_fun = frame->function();
12363 // Not sure when this can happen but skip it just in case.
12364 if (!raw_fun->IsJSFunction())
12365 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012366 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012367 *seen_caller = true;
12368 return false;
12369 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012370 // Skip all frames until we've seen the caller.
12371 if (!(*seen_caller)) return false;
12372 // Also, skip the most obvious builtin calls. We recognize builtins
12373 // as (1) functions called with the builtins object as the receiver and
12374 // as (2) functions from native scripts called with undefined as the
12375 // receiver (direct calls to helper functions in the builtins
12376 // code). Some builtin calls (such as Number.ADD which is invoked
12377 // using 'call') are very difficult to recognize so we're leaving
12378 // them in for now.
12379 if (frame->receiver()->IsJSBuiltinsObject()) {
12380 return false;
12381 }
12382 JSFunction* fun = JSFunction::cast(raw_fun);
12383 Object* raw_script = fun->shared()->script();
12384 if (frame->receiver()->IsUndefined() && raw_script->IsScript()) {
12385 int script_type = Script::cast(raw_script)->type()->value();
12386 return script_type != Script::TYPE_NATIVE;
12387 }
12388 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012389}
12390
12391
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012392// Collect the raw data for a stack trace. Returns an array of 4
12393// element segments each containing a receiver, function, code and
12394// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012395RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012396 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012397 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012398 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12399
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012400 HandleScope scope(isolate);
12401 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012402
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012403 limit = Max(limit, 0); // Ensure that limit is not negative.
12404 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012405 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012406 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012407
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012408 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012409 // If the caller parameter is a function we skip frames until we're
12410 // under it before starting to collect.
12411 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012412 int cursor = 0;
12413 int frames_seen = 0;
12414 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012415 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012416 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012417 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012418 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012419 // Set initial size to the maximum inlining level + 1 for the outermost
12420 // function.
12421 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012422 frame->Summarize(&frames);
12423 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012424 if (cursor + 4 > elements->length()) {
12425 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12426 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012427 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012428 for (int i = 0; i < cursor; i++) {
12429 new_elements->set(i, elements->get(i));
12430 }
12431 elements = new_elements;
12432 }
12433 ASSERT(cursor + 4 <= elements->length());
12434
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012435 Handle<Object> recv = frames[i].receiver();
12436 Handle<JSFunction> fun = frames[i].function();
12437 Handle<Code> code = frames[i].code();
12438 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012439 elements->set(cursor++, *recv);
12440 elements->set(cursor++, *fun);
12441 elements->set(cursor++, *code);
12442 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012443 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012444 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012445 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012446 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012447 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012448 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012449 return *result;
12450}
12451
12452
ager@chromium.org3811b432009-10-28 14:53:37 +000012453// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012454RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012455 ASSERT_EQ(args.length(), 0);
12456
12457 NoHandleAllocation ha;
12458
12459 const char* version_string = v8::V8::GetVersion();
12460
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012461 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12462 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012463}
12464
12465
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012466RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012467 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012468 OS::PrintError("abort: %s\n",
12469 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012470 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012471 OS::Abort();
12472 UNREACHABLE();
12473 return NULL;
12474}
12475
12476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012477RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012478 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012479 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012480 Object* key = args[1];
12481
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012482 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012483 Object* o = cache->get(finger_index);
12484 if (o == key) {
12485 // The fastest case: hit the same place again.
12486 return cache->get(finger_index + 1);
12487 }
12488
12489 for (int i = finger_index - 2;
12490 i >= JSFunctionResultCache::kEntriesIndex;
12491 i -= 2) {
12492 o = cache->get(i);
12493 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012494 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012495 return cache->get(i + 1);
12496 }
12497 }
12498
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012499 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012500 ASSERT(size <= cache->length());
12501
12502 for (int i = size - 2; i > finger_index; i -= 2) {
12503 o = cache->get(i);
12504 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012505 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012506 return cache->get(i + 1);
12507 }
12508 }
12509
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012510 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012511 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012512
12513 Handle<JSFunctionResultCache> cache_handle(cache);
12514 Handle<Object> key_handle(key);
12515 Handle<Object> value;
12516 {
12517 Handle<JSFunction> factory(JSFunction::cast(
12518 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12519 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012520 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012521 // This handle is nor shared, nor used later, so it's safe.
12522 Object** argv[] = { key_handle.location() };
12523 bool pending_exception = false;
12524 value = Execution::Call(factory,
12525 receiver,
12526 1,
12527 argv,
12528 &pending_exception);
12529 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012530 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012531
12532#ifdef DEBUG
12533 cache_handle->JSFunctionResultCacheVerify();
12534#endif
12535
12536 // Function invocation may have cleared the cache. Reread all the data.
12537 finger_index = cache_handle->finger_index();
12538 size = cache_handle->size();
12539
12540 // If we have spare room, put new data into it, otherwise evict post finger
12541 // entry which is likely to be the least recently used.
12542 int index = -1;
12543 if (size < cache_handle->length()) {
12544 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12545 index = size;
12546 } else {
12547 index = finger_index + JSFunctionResultCache::kEntrySize;
12548 if (index == cache_handle->length()) {
12549 index = JSFunctionResultCache::kEntriesIndex;
12550 }
12551 }
12552
12553 ASSERT(index % 2 == 0);
12554 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12555 ASSERT(index < cache_handle->length());
12556
12557 cache_handle->set(index, *key_handle);
12558 cache_handle->set(index + 1, *value);
12559 cache_handle->set_finger_index(index);
12560
12561#ifdef DEBUG
12562 cache_handle->JSFunctionResultCacheVerify();
12563#endif
12564
12565 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012566}
12567
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012568
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012569RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012570 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012571 CONVERT_ARG_CHECKED(String, type, 0);
12572 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012573 return *isolate->factory()->NewJSMessageObject(
12574 type,
12575 arguments,
12576 0,
12577 0,
12578 isolate->factory()->undefined_value(),
12579 isolate->factory()->undefined_value(),
12580 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012581}
12582
12583
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012584RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012585 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12586 return message->type();
12587}
12588
12589
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012590RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012591 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12592 return message->arguments();
12593}
12594
12595
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012596RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012597 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12598 return Smi::FromInt(message->start_position());
12599}
12600
12601
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012602RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012603 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12604 return message->script();
12605}
12606
12607
kasper.lund44510672008-07-25 07:37:58 +000012608#ifdef DEBUG
12609// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12610// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012611RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012612 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012613 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012614#define COUNT_ENTRY(Name, argc, ressize) + 1
12615 int entry_count = 0
12616 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12617 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12618 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12619#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012620 Factory* factory = isolate->factory();
12621 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012622 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012623 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012624#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012625 { \
12626 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012627 Handle<String> name; \
12628 /* Inline runtime functions have an underscore in front of the name. */ \
12629 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012630 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012631 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12632 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012633 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012634 Vector<const char>(#Name, StrLength(#Name))); \
12635 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012636 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012637 pair_elements->set(0, *name); \
12638 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012639 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012640 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012641 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012642 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012643 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012644 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012645 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012646 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012647#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012648 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012649 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012650 return *result;
12651}
kasper.lund44510672008-07-25 07:37:58 +000012652#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012653
12654
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012655RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012656 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012657 CONVERT_CHECKED(String, format, args[0]);
12658 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012659 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012660 LOGGER->LogRuntime(chars, elms);
12661 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012662}
12663
12664
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012665RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012666 UNREACHABLE(); // implemented as macro in the parser
12667 return NULL;
12668}
12669
12670
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012671#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
12672 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
12673 CONVERT_CHECKED(JSObject, obj, args[0]); \
12674 return isolate->heap()->ToBoolean(obj->Has##Name()); \
12675 }
12676
12677ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
12678ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
12679ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
12680ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
12681ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
12682ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
12683ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
12684ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
12685ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
12686ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
12687ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
12688ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
12689ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
12690
12691#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
12692
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012693// ----------------------------------------------------------------------------
12694// Implementation of Runtime
12695
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012696#define F(name, number_of_args, result_size) \
12697 { Runtime::k##name, Runtime::RUNTIME, #name, \
12698 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012699
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012700
12701#define I(name, number_of_args, result_size) \
12702 { Runtime::kInline##name, Runtime::INLINE, \
12703 "_" #name, NULL, number_of_args, result_size },
12704
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012705static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012706 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012707 INLINE_FUNCTION_LIST(I)
12708 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012709};
12710
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012711
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012712MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12713 Object* dictionary) {
12714 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012715 ASSERT(dictionary != NULL);
12716 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12717 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012718 Object* name_symbol;
12719 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012720 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012721 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12722 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012723 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012724 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12725 String::cast(name_symbol),
12726 Smi::FromInt(i),
12727 PropertyDetails(NONE, NORMAL));
12728 if (!maybe_dictionary->ToObject(&dictionary)) {
12729 // Non-recoverable failure. Calling code must restart heap
12730 // initialization.
12731 return maybe_dictionary;
12732 }
12733 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012734 }
12735 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012736}
12737
12738
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012739const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12740 Heap* heap = name->GetHeap();
12741 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012742 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012743 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012744 int function_index = Smi::cast(smi_index)->value();
12745 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012746 }
12747 return NULL;
12748}
12749
12750
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012751const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012752 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12753}
12754
12755
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012756void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012757 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012758 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012759 if (failure->IsRetryAfterGC()) {
12760 // Try to do a garbage collection; ignore it if it fails. The C
12761 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012762 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012763 } else {
12764 // Handle last resort GC and make sure to allow future allocations
12765 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012766 isolate->counters()->gc_last_resort_from_js()->Increment();
12767 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012768 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012769}
12770
12771
12772} } // namespace v8::internal